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

jd.*_*jd. 9 python

是否有一种"简单"的方法将包含数字的str转换为[x,y]整数列表?

# 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]]
Run Code Online (Sandbox Code Playgroud)

顺便说一句,下面的工作,但不会直接称之为...此外,可以假设输入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)
Run Code Online (Sandbox Code Playgroud)

daw*_*awg 22

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')]
Run Code Online (Sandbox Code Playgroud)

这会生成每个长度为2的元组.

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

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

第二个习语是列表理解.如果您希望子元素成为列表,请理解:

>>> [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']]
Run Code Online (Sandbox Code Playgroud)

任何不完整的子元素组都将被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']]
Run Code Online (Sandbox Code Playgroud)

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

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

正如在评论中指出,与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...
Run Code Online (Sandbox Code Playgroud)

如果你的字符串很长,并且你知道你只需要2个元素,那么效率会更高.

  • @Johnsyweb:我实际上认为列表理解和genexp是Python的真正*美丽*功能之一 - 我喜欢它们!Perl有类似的结构; 如果你了解它们会更灵活; 远远低于Python等效的*可读性.我很难得到的东西(对Zen和Perl背景的主观解释)是Python对小辅助函数的偏见.必须追踪小功能,而不是一行中的所有内容.权衡我猜.谢谢你的评论.由于有用的评论,我每天都学到更多.: - } (2认同)
  • @drewk:我完全同意.关于小辅助函数的好处是它们非常容易进行单元测试,并且(有意义的名称)使它易于阅读*你在做什么(不是*你是怎么做的).因此,如果您在www中搜索"可执行伪代码",您会获得很多关于Python的点击! (2认同)

Fel*_*ing 15

一种选择:

>>> num_str = '5,4,2,4,1,0,3,0,5,1,3,3,4,3,3,5'
>>> l = num_str.split(',')
>>> zip(l[::2], l[1::2])
[('5', '4'), ('2', '4'), ('1', '0'), ('3', '0'), ('5', '1'), ('3', '3'), ('4', '3'), ('3', '5')]
Run Code Online (Sandbox Code Playgroud)

参考:str.split(),zip(),关于序列类型和切片的一般信息

如果你真的想要整数,你可以先使用map以下命令将列表转换为整数:

>>> l = map(int, num_str.split(','))
Run Code Online (Sandbox Code Playgroud)

说明:

split创建单个元素的列表.诀窍是切片:语法是list[start:end:step].l[::2]将返回从第一个元素开始的每个第二个元素(所以第一个,第三个,......),而第二l[1::2]个元素从第二个元素返回每个第二个元素(所以第二个,第四个,......).

更新:如果您确实需要列表,可以map在结果列表中再次使用:

>>> xy_list = map(list, xy_list)
Run Code Online (Sandbox Code Playgroud)

请注意,@ Johnsyweb的答案可能更快,因为它似乎没有做任何不必要的迭代.但实际差异当然取决于列表的大小.


Joh*_*web 11

#!/usr/bin/env python

from itertools import izip

def pairwise(iterable):
    "s -> (s0,s1), (s2,s3), (s4, s5), ..."
    a = iter(iterable)
    return izip(a, a)

s = '5,4,2,4,1,0,3,0,5,1,3,3,4,3,3,5'
fields = s.split(',')
print [[int(x), int(y)] for x,y in pairwise(fields)]
Run Code Online (Sandbox Code Playgroud)

取自@ martineau我的问题的回答,发现这个问题非常快.

输出:

[[5, 4], [2, 4], [1, 0], [3, 0], [5, 1], [3, 3], [4, 3], [3, 5]]
Run Code Online (Sandbox Code Playgroud)