Python - 使用map(sys.stdin.readline())存储字符串和整数

7
如果输入包含以空格分隔的 int 行,如下所示-
1 3

我可以使用map()函数将其映射到一个数组中。
arr = map(int,sys.stdin.readline().split())

甚至可以通过两个单独的变量

n,m = map(int,sys.stdin.readline().split())

有没有一种方法可以使用相同的方式读取包含混合数据类型的输入行。例如-

foo 3

其中foo是一个字符串,而3是一个整数?


这些数字是否总是正整数? - Padraic Cunningham
第一个输入始终被解释为字符串,第二个输入始终被解释为整数,这是否是预期的?如果是这样,那么这将改变输入应该如何处理,而且没有任何答案真正涉及到这一点。 - user2357112
@PadraicCunningham,实际上这些数字也可以是负数。 - deathstroke
@user2357112 是的,通常预期第一个输入为字符串,第二个输入为整数(可以是正数或负数)。这会如何改变输入的处理方式? - deathstroke
@Deathstroke:我已经发布了一个回答,描述了如何处理它。 - user2357112
5个回答

4
为了做到这一点,您需要能够区分可以表示整数和不能表示整数的字符串。例如:

要做到这一点,您应该能够区分可以表示整数和不能表示整数的字符串。一个例子是:

def foo(s):
    try:
        return int(s)
    except ValueError:
        return s

然后您可以正常使用map

map(foo, sys.stdin.readline().split())

上述输入行:
abcdef 110

将会输出:

['abcdef', 110]

太棒了,像魔法一样顺利。谢谢。 :-) - deathstroke
比起尝试LBYL(Look Before You Leap)来确定数字是否为有效的“int”,这种方法要干净得多。 - abarnert

4
如果您始终有一串字符和非负整数:
import sys
n, m = map(lambda x: (str, int)[x.isdigit()](x) ,sys.stdin.readline().split(None, 1)) 


print(n,m)

但是,即使只期望一个类型,使用try/except转换用户输入始终是最安全的方法。

根据要求,检查负数是可能的:

import sys
n, m = map(lambda x: (str, int)[x.isdigit() or x.strip("-").isdigit()](x) ,sys.stdin.readline().split())


print(n, m)

但是--10 --10--也会通过测试,但会导致错误,所以只适用于您特定的情况。


@Deathstroke,是的,但这只是一个有趣的解决方案,使用try/except是最安全的方式,它还允许负数。 - Padraic Cunningham
@PadraicCunningham,但是如果我确定输入将是预期的形式,我是否需要检查安全性呢?我的意思是,我将使用它来解决在线评测中的算法问题。所以我想我应该选择更快而不是更安全的东西? - deathstroke
即使处理负数仍然不是真正正确的。0123是所有数字,但不是int的有效参数(3.x),或被解释为八进制(2.x)。一些Unicode数字在Python int中是有效的,而另一些则不是。0x12ab是一个有效的Python int,但它不是所有数字。试图编写一个在调用int之前预测所有计数为有效int表示的函数非常困难。如果您想要任何Python int,只需使用try调用int。如果您想要其他东西,请明确定义您想要的内容,然后实现它。 - abarnert
我不明白“在线代码问题网站”在这里有什么区别。他说“比更安全的东西快”,但这显然在算法上既不快也不慢,只有微小的常数差异 - 而且,复杂的LBYL检查可能比try/except更慢。此外,在线问题不就是你应该期望看到会破坏天真代码的不寻常“诡计输入”的地方吗? - abarnert
我不会指望它们是"随机"的,我会期望编写测试的人精心选择它们。例如,我知道 Codility(更多用于面试筛选而不是竞赛类型问题)经常提出一些明确测试错误假设的问题,比如在没有理由假设的情况下,将问题中的“数字”解释为“正整数”。 - abarnert
显示剩余7条评论

3
你可以使用str.isdigit来测试字符串是否可以转换为整数数字。
>>> inpt = "foo 3"
>>> [int(s) if s.isdigit() else s for s in inpt.split()]

当然,您也可以使用mapsys.stdin.readline以及lambda来完成相同的操作。
>>> map(lambda s: int(s) if s.isdigit() else s, sys.stdin.readline().split())
foo 4
['foo', 4]

如果您想支持各种数据类型,可以尝试使用literal_eval,如果不起作用,则回退到基本字符串。

import ast
def try_eval(string):
    try:
        return ast.literal_eval(string)
    except ValueError:
        return string

>>> map(try_eval, "42 3.14 foo 'bar' [1,2,3]".split())
[42, 3.1400000000000001, 'foo', 'bar', [1, 2, 3]]

isdigit 实际上并不测试字符串是否可以转换为整数,因此您不应该将其用于此目的。 - abarnert
@abarnert 我知道 isdigit 不能处理负数,但是是否存在这样一种情况:isdigit 返回 True,但强制转换为 int 会失败? - tobias_k
从我的经验来看,在至少某些2.x版本的宽字符集中,非BMP Unicode数字可以通过isdigit函数,但被int函数拒绝。同时,isdigit函数还有其他无法处理的情况,比如"+3"和"2",以及在3.0-3.2窄字符集中的非BMP Unicode数字。我不知道这些是否是唯一的情况,但这本身就是不使用isdigit函数的原因:"我认为这可能是要测试的唯一问题"只意味着"我无法想出如何编写完整的测试覆盖"。相比之下,将int函数放在try块中则保证能够正常工作。 - abarnert

2

当您需要对输入的每个元素应用相同的转换时,可以使用map。但这并不适合您的用例;您希望以不同的方式处理两个输入。由于数据具有固定的字符串格式和整数格式,因此最好以始终产生该格式的方式进行解析:

x, y = raw_input().split()
y = int(y)

如果您有更多的列,您可以制作一个列表,列出如何处理每一列所需使用的函数:

handlers = [str, int, int, str, float, int, int]
a, b, c, d, e, f, g = [f(x) for (f, x) in zip(handlers, raw_input().split())]

其他答案提供的解决方案没有考虑输入格式的固定性。如果用户输入:
31 42

x 应该是 "31",而不是 31,如果用户输入了

foo bar

应该将这看作一种错误,而不是将"bar"分配给y


从问题中似乎并不清楚他是在问这个答案还是另一个答案...所以无论他想要什么,指出来肯定是值得的。 - abarnert
1
@abarnert:根据评论中的澄清,我相信这是正确的解释,但我可能错了。 - user2357112
1
@user2357112 和 @abarnet: 为了澄清,我想说一下,我期望的输入格式始终是 foo 42foo -42 的形式。 输入不会包含 32 42foo bar。它始终以 str int 的格式出现。 - deathstroke

1
如果您不需要任何高级功能,可以快速设置“try/except”。

e.g.,

def convert(x):
    try:
        f = float(x)
        i = int(f)
        x = i if i == f else f
    except:
        pass
    return x

arr = map(convert, sys.stdin.readline().split())

是的!这就是我在寻找的。 - deathstroke
啊,是的。现在应该已经修好了。 - AMacK
它对我有效。'abc 123 4.5 6.7' 返回 ['abc', 123, 4.5, 6.7]。你能解释一下我错过了什么吗? - AMacK
@AMacK:这不是你最初要求的,但是……通过浮点数转换为整数并不总是与直接转换为整数相同,也不是一个好主意。尝试使用“'100000000000000000000000'”,你会得到“[99999999999999991611392]”。 - abarnert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接