最Pythonic(且高效)的将列表成对嵌套的方法

5

我的列表是:

mylist=[1,2,3,4,5,6]

我想把mylist转换成一对一对的列表:

[[1,2],[3,4],[5,6]]

有没有一种pythonic的方法来做到这一点?列表推导?itertools?
5个回答

9

没错,列表推导式是我通常的做法:

>>> groupsize = 2
>>> [mylist[x:x+groupsize] for x in range(0,len(mylist),groupsize)]
[[1,2],[3,4],[5,6]]
>>> groupsize = 3
>>> [mylist[x:x+groupsize] for x in range(0,len(mylist),groupsize)]
[[1,2,3],[4,5,6]]

我使用range来确保可移植性,如果你正在使用Python 2(很可能是),请将range更改为xrange以节省内存。


8

我偏爱的技术:

>>> mylist = [1, 2, 3, 4, 5, 6]
>>> mylist = iter(mylist)
>>> zip(mylist, mylist)
[(1, 2), (3, 4), (5, 6)]

我通常使用生成器而非列表,因此第二行通常不需要。


2
为了增加乐趣,将zip更改为zip(* [mylist] * groupsize)以允许通用组大小。当然,使用zip的方法始终会在处理长度不能被所需组大小整除的列表时出现问题。 - Josiah
这似乎是实现此操作的“最Pythonic”的方式。 - Brian M. Hunt
@BrianM.Hunt 我不确定我是否同意。Python的禅则说“简单胜于复杂”,如果你不完全理解zip和迭代器的工作原理,那就很难称之为简单。虽然这绝对是最聪明的方法。 - Josiah
@Josiah 我有点同意你的看法,尽管如果一个人可以将两个不同的生成器压缩在一起,那么他们就知道可以按顺序将一个生成器与自身压缩。我发现这种技术相当安全。特别是如果你选择 (x, y) in zip(points, points),例如,它可能很明显。 - Rusty Rob

6

另一种方法:

zip( mylist[:-1:2], mylist[1::2] )

这将产生一个元组列表:

>>> zip(mylist[:-1:2],mylist[1::2])
[(1, 2), (3, 4), (5, 6)]

如果你真的想要一个列表的列表:

map(list, zip(mylist[:-1:2],mylist[1::2]))

5

请查看itertools文档中的“grouper”配方:

def grouper(n, iterable, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

1
这将在6个项目序列上产生5对,这是不正确的。如果你想要一个itertools的配方,它应该是“grouper”。 - Steven Rumbalski

2

[mylist[2*n:2*n+2] for n in xrange(len(mylist)/2)]

这个解决方案结合使用列表推导和切片来从原始列表中提取成对的序列,并构建一个切片列表。

或者,[mylist[n:n+2] for n in xrange(0, len(mylist), 2)]是相同的,除了xrange以两个为单位计数而不是切片。感谢Steven Rumbalski的建议。

现在,有一种不同的解决方案:这里是一种利用zip和临时函数而不是中间赋值的方法:

>>> (lambda i: zip(i, i))(iter(mylist))
[(1, 2), (3, 4), (5, 6)]

5
比必要的复杂--只需将xrange按2步增加,大部分数学问题就会消失。 - Steven Rumbalski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接