python:将“5,4,2,4,1,0”转换为,,]
有没有一种“直接”的方式来将一个包含数字的string转换为[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]]
顺便说一下,下面的工作,但不会直接调用它…此外,可以假设inputstr已被validation,以确保它只包含偶数的数字交错逗号。
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)
在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')]
第二个习语是列表parsing 。 如果你想让子元素成为列表,换一个理解:
>>> [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()截断。 所以,如果你的string不是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+,你也可以用一个生成器expression式replace列表理解,用下面的代替[ ]
( )
>>> 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...
如果你的string很长,而且你知道你只需要两个元素,这就更有效率了。
一个选项:
>>> 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')]
参考 : str.split()
, zip()
, 有关序列types和切片的一般信息
如果你真的需要整数,你可以使用map
首先将列表转换为整数:
>>> l = map(int, num_str.split(','))
说明:
split
创build单个元素的列表。 技巧是切片:语法是list[start:end:step]
。 l[::2]
将返回从第一个元素(第一个,第三个…)开始的每个第二个元素,而第二个slice l[1::2]
从第二个元素返回第二个元素(所以第二,第四,…)。
更新:如果您确实需要列表,则可以在结果列表中再次使用map
:
>>> xy_list = map(list, xy_list)
请注意, @ Johnsyweb的答案可能更快,因为它似乎没有做任何不必要的迭代。 但实际的差异当然取决于列表的大小。
#!/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)]
从@ martineau回答 我的问题 ,我发现它非常快。
输出:
[[5, 4], [2, 4], [1, 0], [3, 0], [5, 1], [3, 3], [4, 3], [3, 5]]
首先,使用split
来创build一个数字列表(就像所有其他的答案一样)。
num_list = num_str.split(",")
然后,转换为整数:
num_list = [int(i) for i in num_list]
然后,使用itertools groupby
配方:
from itertools import izip_longest def grouper(n, iterable, fillvalue=None): "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" args = [iter(iterable)] * n return izip_longest(fillvalue=fillvalue, *args) pair_list = grouper(2, num_list)
当然,如果你节俭,你可以把它压缩成一行:
pair_list = grouper(2, [int(i) for i in num_str.split(",")]
>>> num_str = '5,4,2,4,1,0,3,0,5,1,3,3,4,3,3,5' >>> inums = iter([int(x) for x in num_str.split(',')]) >>> [[x, inums.next()] for x in inums] [[5, 4], [2, 4], [1, 0], [3, 0], [5, 1], [3, 3], [4, 3], [3, 5]] >>>
编辑: @drewk清理这个处理偶数或奇数长度列表:
>>> f = '5,4,2,4,1,0,3,0,5,1,3,3,14,32,3,5' >>> li = [int(n) for n in f.split(',')] >>> [li[i:i+2] for i in range(0, len(li), 2)] [[5, 4], [2, 4], [1, 0], [3, 0], [5, 1], [3, 3], [14, 32], [3, 5], [7]]
您可以使用分割function缩短第一部分(将“1,2,3”转换为[1,2,3]):
num_list = num_str.split(",")
可能有一个更简单的方法来获得对,但我会做这样的事情:
xy_pairs = [] for i in range(0, len(num_list), 2): x = num_list[i] y = num_list[i + 1] xy_pairs.append([x, y])
另外,因为这些都是定义长度(2)的列表,所以你应该使用一个元组:
xy_pairs.append((x, y))
有一个发电机可能会很有趣。 这是一个生成器expression式:
import re ch = '5,4,2,4,1,0,3,0,5,1,3,3,14,32,3,5' genexp = ( map(int,ma.groups()) for ma in re.finditer('(\d+)\s*,\s*(\d+)',ch) )
#declare the string of numbers str_nums = '5,4,2,4,1,0,3,0,5,1,3,3,14,32,3,5' #zip two lists: the even elements with the odd elements, casting the strings to integers zip([int(str_nums.split(',')[i]) for i in range(0,len(str_nums.split(',')),2)],[int(str_nums.split(',')[i]) for i in range(1,len(str_nums.split(',')),2)]) """ Of course you would want to clean this up with some intermediate variables, but one liners like this is why I love Python :) """
这是一个更广义的函数,适用于不同的块大小,并在需要时附加提醒
def breakup(mylist,chunks): mod = len(mylist) % chunks if mod == 0: ae = [] elif mod == 1: ae = mylist[-1:] else: ae = [tuple(mylist[-mod:])] return zip(*[iter(mylist)]*chunks) + ae num_str = '5,4,2,4,1,0,3,0,5,1,3,3,14,32,3,5' lst = map(int,num_str.split(',')) print breakup(lst,2)
OUT:[(5,4),(2,4),(1,0),(3,0),(5,1),(3,3),(14,32),(3,5) ]
也许这个?
a = "0,1,2,3,4,5,6,7,8,9".split(",") [[int(a.pop(0)), int(a.pop(0))] for x in range(len(a)/2)]