一尘不染

python:将“ 5,4,2,4,1,0”转换为[[5,4],[2,4],[1,0]]

python

是否有“简单”的方法将包含数字的str转换为[x,y] int列表?

# from: '5,4,2,4,1,0,3,0,5,1,3,3,14,32,3,5'
# to: [[5, 4], [2, 4], [1, 0], [3, 0], [5, 1], [3, 3], [14, 32], [3, 5]]

顺便说一下,下面的方法可以工作,但是并不能简单明了。。。此外,可以假定输入str已经过验证,以确保它仅包含偶数个逗号分隔的数字。

num_str = '5,4,2,4,1,0,3,0,5,1,3,3,14,32,3,5'
numpairs_lst = []      # ends up as [[5, 4], [2, 4], [1, 0], ...]

current_num_str = ''   # the current num within the str; stop when a comma is found
xy_pair = []           # this is one of the [x,y] pairs -> [5, 4] 
for ix,c in enumerate(num_str):
    if c == ',':
        xy_pair.append(int(current_num_str))
        current_num_str = ''
        if len(xy_pair) == 2:
            numpairs_lst.append(xy_pair)
            xy_pair = []
    else:
        current_num_str += c

# and, take care of last number...
xy_pair.append(int(current_num_str))
numpairs_lst.append(xy_pair)

阅读 134

收藏
2020-12-20

共1个答案

一尘不染

Python中有两个重要的单行习惯用法,可以使这种“简单易懂”。

第一个习惯用法是使用zip()。从Python文档中:

保证了可迭代对象的从左到右的评估顺序。这使得使用zip(* [iter(s)] * n)将数据系列聚类为n个长度的组成为可能。

因此,适用于您的示例:

>>> num_str = '5,4,2,4,1,0,3,0,5,1,3,3,14,32,3,5'
>>> zip(*[iter(num_str.split(","))]*2)
[('5', '4'), ('2', '4'), ('1', '0'), ('3', '0'), ('5', '1'), 
('3', '3'), ('14', '32'), ('3', '5')]

产生每个长度为2的元组。

如果您希望子元素的长度不同:

>>> zip(*[iter(num_str.split(","))]*4)
[('5', '4', '2', '4'), ('1', '0', '3', '0'), ('5', '1', '3', '3'), 
('14', '32', '3', '5')]

第二个成语是列表理解。如果您希望子元素成为列表,则可以理解以下内容:

>>> [list(t) for t in zip(*[iter(num_str.split(","))]*4)]
[['5', '4', '2', '4'], ['1', '0', '3', '0'], ['5', '1', '3', '3'], 
['14', '32', '3', '5']]
>>> [list(t) for t in zip(*[iter(num_str.split(","))]*2)]
[['5', '4'], ['2', '4'], ['1', '0'], ['3', '0'], ['5', '1'], ['3', '3'], 
['14', '32'], ['3', '5']]

zip()将截断所有不完整的子元素组。因此,例如,如果您的字符串不是2的倍数,则将丢失最后一个元素。

如果要返回不完整的子元素(即,如果您num_str不是子元素长度的倍数),请使用切片成语

>>> l=num_str.split(',')
>>> [l[i:i+2] for i in range(0,len(l),2)]
[['5', '4'], ['2', '4'], ['1', '0'], ['3', '0'], ['5', '1'], 
['3', '3'], ['14', '32'], ['3', '5']]
>>> [l[i:i+7] for i in range(0,len(l),7)]
[['5', '4', '2', '4', '1', '0', '3'], ['0', '5', '1', '3', '3', '14', '32'], 
['3', '5']]

如果希望每个元素都是一个int,则可以在此处讨论的其他转换之前应用它:

>>> nums=[int(x) for x in num_str.split(",")]
>>> zip(*[iter(nums)]*2)
# etc etc etc

正如评论中所指出的那样,在Python
2.4+中,您还可以通过将替换为来用生成器表达式替换列表推导:[ ]``( )

 >>> nums=(int(x) for x in num_str.split(","))
 >>> zip(nums,nums)
 [(5, 4), (2, 4), (1, 0), (3, 0), (5, 1), (3, 3), (14, 32), (3, 5)]
 # or map(list,zip(nums,nums)) for the list of lists version...

如果您的字符串很长,并且您知道只需要2个元素,则效率更高。

2020-12-20