比较子列表并合并它们

时间:2016-11-13 13:29:39

标签: python

我有一个包含大量子列表的列表,这些子列表最初是数字对,所以它看起来像:

list = [[2, 3], [4, 5], [7, 8], [8, 9], [11, 12], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [20, 21]]

我想要的是将子列表的最后一位数与下一个子列表中的第一位数进行比较,如果它们匹配,则将它们合并到一个子列表中。因此,两个匹配的子列表的输出将是这样的:

output = [[7, 8, 9]]

当然,如果有一行匹配的子列表,那么将它们全部合并到一个大的子列表中。

output = [[14, 15, 16, 17, 18, 19]]

我在考虑使用itemgetter作为比较的一种键。所以可能是这样的:

prev_digit = itemgetter(-1)
next_digit = itemgetter(0)

但最初我意识到由于缺乏知识,我真的不明白如何在Python中使用它。我试着考虑一个for循环,但它没有解决,因为我不知道如何实现这些"键"。

对于某些灵感,我使用了Python, comparison sublists and making a list,但即便如此,我仍然没有解决方案。

另外,由于我的列表有点大(从人的角度来看,就像千对或者东西),我对最有效的方法非常感兴趣。

是的,我是Python的新手,所以我非常感谢好的解释。当然我可以google,所以你可以避免深入解释函数,但是像一般逻辑一样会很好。

2 个答案:

答案 0 :(得分:2)

我想我曾经写过这个。它可以通过列表中的一次传递来完成。

alist = [[2, 3], [4, 5], [7, 8], [8, 9], [11, 12], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [20, 21]]

l = [alist[0][:]]
for e in alist[1:]:
   if l[-1][-1] == e[0]:
      l[-1].append(e[1])
   else:
      l.append(e[:])

代码从第一对开始读取。循环其余部分。检查最后一个列表的最后一个元素是否与该对的第一个元素相同。如果这样追加第二个元素,则将该对添加到列表中。

这会导致l

[[2, 3], [4, 5], [7, 8, 9], [11, 12], [14, 15, 16, 17, 18, 19], [20, 21]]

如果您只想要我建议的最大子列表:

>>> l = [[2, 3], [4, 5], [7, 8, 9], [11, 12], [14, 15, 16, 17, 18, 19], [20, 21]]
>>> max(l, key=len)
[14, 15, 16, 17, 18, 19]

并评估:

>>> alist = [[2, 3], [4, 5], [7, 8], [8, 9], [11, 12], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [20, 21]]
>>> 
>>> l = [alist[0][:]]
>>> for e in alist[1:]:
...    if l[-1][-1] == e[0]:
...       l[-1].append(e[1])
...    else:
...       l.append(e[:])
... 
>>> l
[[2, 3], [4, 5], [7, 8, 9], [11, 12], [14, 15, 16, 17, 18, 19], [20, 21]]
>>> alist
[[2, 3], [4, 5], [7, 8], [8, 9], [11, 12], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [20, 21]]

并进行比较。 reduce解决方案需要6.4 usecs:

$ python -mtimeit "list = [[2, 3], [4, 5], [7, 8], [8, 9], [11, 12], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [20, 21]]" "reduce(lambda x,y: x[:-1] + [x[-1] + y[1:]] if x[-1][-1] == y[0] else x + [y], list[1:], [list[0]])"
100000 loops, best of 3: 6.4 usec per loop

for循环需要3.62 usecs:

$ python -mtimeit "alist = [[2, 3], [4, 5], [7, 8], [8, 9], [11, 12], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [20, 21]]" "l = [alist[0][:]]" "for e in alist[1:]:" "   if l[-1][-1] == e[0]:" "      l[-1].append(e[1])" "   else:" "      l.append(e[:])"
100000 loops, best of 3: 3.62 usec per loop

在Python 2.7.3上。 for循环速度提高了56%。由于列表连接的成本取决于两个列表的长度之和,因此输入较大时差异可能更明显。而附加到列表稍微便宜一点。

答案 1 :(得分:1)

使用reduce

>>> reduce(
... lambda x,y: x[:-1] + [x[-1] + y[1:]] if x[-1][-1] == y[0] else x + [y],
... list[1:],
... [list[0]]
... )
[[2, 3], [4, 5], [7, 8, 9], [11, 12], [14, 15, 16, 17, 18, 19], [20, 21]]

<强>解释

以下是与reduce一起使用的扩展形式的lamdba函数。

def mergeOverlappingRange(x, y):
    if x[-1][-1] == y[0]: 
        return x[:-1] + [x[-1] + y[1:]]
    else:
        return x + [y]

reduce(mergeOverlappingRange, list[1:], [list[0]])