列表的切片模式

Slice pattern for list

我有一个列表,其中有未定义数量的元素:

l1 = [a, b, c, d ...]

我需要创建一个列表:

l2 = [[a,a],[a,b],[b,b],[b,c],[c,c],[c,d],[d,d],[d,e],...]

现在,为了获得l2,我是这样做的:

l1 = sorted(l1*4)[1:-1]
l2 = [l1[x:x+2] for x in xrange(0,len(l1),2)]

它可以工作,但我不喜欢它,因为如果 l1 中的元素数量很大,那么这段代码将占用大量内存 (*4) 和时间(排序)消耗。您对如何执行此操作有任何提示吗?

由于您需要在内存使用方面的最佳代码,因此最好的方法是使用生成器,在这种情况下您可以使用 itertools 模块:

>>> def pair_creator(iterator):
...     pairs = chain.from_iterable((repeat(i,2) for i in iterator))
...     forward, pairs = tee(pairs)
...     next(forward)
...     return zip(pairs,forward)

您在这里所需要做的就是创建一个迭代器,其中包含前面项目的重复对。

new = chain.from_iterable((repeat(i,2) for i in l1))

然后使用 tee 从当前迭代器创建 2 个独立的迭代器 然后使用 next 消耗其中一个的第一项 他们使用 zip (izip在 python 2.X) 中获取正确的列。

演示:

>>> l1 = range(10)
>>> pair_creator(l1)
[(0, 0), (0, 1), (1, 1), (1, 2), (2, 2), (2, 3), (3, 3), (3, 4), (4, 4), (4, 5), (5, 5), (5, 6), (6, 6), (6, 7), (7, 7), (7, 8), (8, 8), (8, 9), (9, 9)]
>>> 

假设初始列表是有序的:

l1 = [a, b, c, d ...]
l2 = []
for ii, x in enumerate(l1[:-1]):
    l2.append([x,x])
    l2.append([x,l1[ii+1])
l2.append([l1[-1],l1[-1]) # last element
f         = lambda (x, y): [[x, x], [x, y]]
concat    = lambda xs: sum(xs, [])
concatMap = lambda f, xs: concat(map(f, xs))

这是你的函数:

fn = lambda xs: concatMap(f, zip(xs, xs[1:]))

以下是我如何使用列表推导来做到这一点:

In [46]: from itertools import izip, islice

In [47]: l1 = ['a', 'b', 'c', 'd', 'e']
In [48]: l2=[x for (a,b) in izip(l1, islice(l1, 1,None)) for x in ([a,a],[a,b])] ; l2 += [[b,b]]

In [49]: l2
Out[49]: 
[['a', 'a'],
 ['a', 'b'],
 ['b', 'b'],
 ['b', 'c'],
 ['c', 'c'],
 ['c', 'd'],
 ['d', 'd'],
 ['d', 'e'],
 ['e', 'e']]