我有一个元组列表,长度为 x:
[(a1,a2,a3,a4),(b1,b2,b3,b4),(c1,c2,c3,c4),(d1,d2,d3,d4), ... ,(x1,x2,x3,x4)]
我想创建一个新的元组列表如下:
[(a1,a2,b1,b2),(c1,c2,d1,d2),(e1,e2,f1,f2), ... ,((x-1)1,(x-1)2,x1,x2)]
如您所见,子列表的所有第三个和第四个元素都消失了,并且相邻的子列表已合并。
我可以用几个循环来完成它,但我正在寻找优雅的 Python 风格的方式来完成它。
最佳答案
我思考了什么是 Pythonic 方式,得出的结论是如果您不需要序列,那么接受任何迭代器 将是 python 式的。 Martijn 的 xrange 方法在这个意义上并不是最 pythonic 的,而且确实是 Martijn 的石斑鱼方法
result = [ i[:2] + j[:2] for i, j in izip(*[iter(l)] * 2) ]
是最 pythonic 的,因为它接受任何类型的可迭代对象。
[iter(l)] * 2
使用两个元素中的相同 迭代器生成一个 2 大小的列表。这比我对上面的 next
的尝试更快的原因是对 next()
的调用是昂贵的(所有函数调用相对于内联运算符的使用和元组的构造,CPython 上的属性/名称解析速度较慢)。
这是最简单明了的解决方案,我发现它是最符合 Pythonic 的,并且具有严格的列表:
l = [('a1', 'a2', 'a3', 'a4'), ('b1', 'b2', 'b3', 'b4'), ('c1', 'c2', 'c3', 'c4'), ('d1', 'd2', 'd3', 'd4')]
y = [ i[:2] + j[:2] for i, j in zip(l[::2], l[1::2]) ]
print y
打印
[('a1', 'a2', 'b1', 'b2'), ('c1', 'c2', 'd1', 'd2')]
但是它不是最有效的,因为 zip
和切片将在 Python 2 上创建临时列表,因此为了加快速度,可以使用 itertools.izip
使用 islice
生成生成解决方案。
但是,实际上可以在这里滥用迭代器来制作相当高效的代码,尽管不是很 Pythonic
i = iter(l)
n = i.next
result = [ j[:2] + n()[:2] for j in i ]
print result
打印
[('a1', 'a2', 'b1', 'b2'), ('c1', 'c2', 'd1', 'd2')]
列表理解中的for
隐式调用迭代器i
上的next()
并将结果赋值给j
;在列表理解体中,我们显式推进相同的迭代器以获取下一个元组。然后通过元组切片,我们获取偶数元组(从 0 开始)的前 2 个元素,并将下一个元组的前 2 个元素连接到它。然而,如果原始列表中的元素数量不是偶数,此代码将导致 StopIteration
异常,这与 slice'n'zip 解决方案不同,后者只会默默地丢弃最后一个奇数元组。
关于python - 通过组合相邻元素并削减元素的长度来转换元组列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28591599/