我想把下面的字符串转换为:
s = '1|2|a|b'
to
[1, 2, 'a', 'b']
是否可以在一行内完成转换?
是否可以用一行代码进行转换?
是的,这是可能的。但是怎么做呢?
方法的算法
使用 str.split
将字符串拆分为其组成部分。其输出为:
>>> s = '1|2|a|b'
>>> s.split('|')
['1', '2', 'a', 'b']
现在我们已经解决了一半的问题。接下来我们需要遍历拆分后的字符串,并检查每个元素是字符串还是整数。为此,我们使用
str.isdigit
用于判断元素是int
还是str
。可以轻松地将列表推导式写成 [i for i in s.split('|')]
。但是如何在其中添加一个if
子句呢?这在一行列表推导式:if-else变体中有介绍。现在我们知道哪些元素是int
,哪些不是,我们就可以轻松地对其调用内置的int
函数了。
因此最终代码将如下所示
[int(i) if i.isdigit() else i for i in s.split('|')]
现在进行一个小演示:
>>> s = '1|2|a|b'
>>> [int(i) if i.isdigit() else i for i in s.split('|')]
[1, 2, 'a', 'b']
正如我们所看到的,输出结果与预期相符。
请注意,如果要转换的类型很多,则此方法不适用。
对于负数或一个语句里包含多种类型的数据,你不能使用同一行来完成它。但是你可以使用一个函数,该函数可以适用于多种类型,其中使用了ast.literal_eval
:
from ast import literal_eval
def f(s, delim):
for ele in s.split(delim):
try:
yield literal_eval(ele)
except ValueError:
yield ele
s = '1|-2|a|b|3.4'
print(list(f(s,"|")))
[1, -2, 'a', 'b', 3.4]
ast.literal_eval
。它非常有用。现在我可以使用两行代码将数据转换为多种类型:from ast import literal_eval
和 [literal_eval(e) if e[-1].isdigit() else e for e in s.split('|')]
。 - wanniklist(map(literal_eval, re.sub('(?!\|)([A-Za-z]+)', "'" + r"\1" + "'", s).split("|")))
,将字符用引号括起来。但是函数方法更加健壮可靠。 - Padraic Cunninghammap
方法:>>> s='1|2|a|b'
>>> l = map(lambda x: int(x) if x.isdigit() else x, s.split('|'))
>>> l
[1, 2, 'a', 'b']
>>> s='1|2|a|b'
>>> l = list(map(lambda x: int(x) if x.isdigit() else x, s.split('|')))
>>> l
[1, 2, 'a', 'b']
由于Python3中的map
会返回一个生成器,因此您必须将其转换为list
def convert(input):
converters = [int, float, json.loads]
for converter in converters:
try:
return converter(input)
except (TypeError, ValueError):
pass
# here we assume if all converters failed, it's just a string
return input
s = "1|2.3|a|[4,5]"
result = [convert(x) for x in s.split("|")]
s = '1|2|a|b|[1, 2, 3]|(1, 2, 3)'
print [eval(x) if not x.isalpha() else x for x in s.split("|")]
# [1, 2, 'a', 'b', [1, 2, 3], (1, 2, 3)]
如果存在诸如“b1”之类的元素,则此操作将失败。
int
和string
但我正在思考如何将该解决方案用于float
。 - wannik