2

我正在尝试从具有相同第一项和第三项但仅保留第一项的列表中删除列表。示例列表和输出:

li=[ [2,4,5], [1,3,5], [1,6,5] ]
output_list = [ [2,4,5], [1,3,5] ]

我编写的代码需要很长时间才能执行,因为原始列表包含数百万个列表。

b_li = []
output_list = []
for x in li:
    s = [ x[0], x[2] ]
    if s not in b_li:
        b_li.append(s)
        output_list.append(x)

如何改进代码?提前致谢。

4

4 回答 4

2

使用一个集合来存储看到的元素。那更快:

seen = set()
res = []
for entry in li:
    cond = (entry[0], entry[2])
    if cond not in seen:
        res.append(entry)
        seen.add(cond)


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

添加

此外,花在考虑告诉变量名称上的时间通常是很好的。通常情况下,作为一次性解决方案的事情首先存在的时间比预期的要长得多。

于 2013-06-01T23:03:49.950 回答
2

改进版:

b_li = set()
output_list = []
b_li_add = b_li.add
output_list_append = output_list.append
for x in li:
    s = (x[0], x[2])
    if s not in b_li:
        b_li_add(s)
        output_list_append(x)

这些变化是:

  • 使用set()forb_li可以加快查找速度。
  • s变成一个元组,因为不需要将唯一的第一个和第三个元素存储为列表。
  • 减少了函数查找,这也加快了代码速度。
于 2013-06-01T23:04:11.077 回答
1

利用OrderedDict和字典具有唯一键的事实。

>>> from collections import OrderedDict
>>> li=[ [2,4,5], [1,3,5], [1,6,5] ]
>>> OrderedDict(((x[0], x[2]), x) for x in reversed(li)).values()
[[1, 3, 5], [2, 4, 5]]
于 2013-06-02T01:15:34.310 回答
0

这是一个基于@iurisilvio 的迭代器注释的解决方案,它与其他基于 - 的解决方案itertools.compress结合使用set。不是在输入列表中建立一个output_listfrom 元素,而是selector在一对一的基础上建立一个包含布尔值的列表,该基础与输入列表中的元素有关。值True表示输入列表中的相应元素应保留在输出中。然后selector可以通过将其应用于输入列表itertools.compress以产生输出可迭代。

from itertools import compress
li=[ [2,4,5], [1,3,5], [1,6,5] ]
b_li = set()
selectors = []
for x in li:
    s = (x[0], x[2])
    if s not in b_li:
        b_li.add(s)
        selectors.append(True)
    else:
        selectors.append(False)

for x in compress(li, selectors):
  print x
[2, 4, 5]
[1, 3, 5]
于 2013-06-01T23:22:34.213 回答