2013-06-01 215 views
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) 

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

+1

使用一个集合而不是一个列表来记录看到的第一个/最后一个对。 – Marcin

+1

根据您的使用情况,您可以返回迭代器而不是创建新列表。它会为你节省大量的内存。 – iurisilvio

+0

可能重复? http://stackoverflow.com/questions/15037226/python-remove-duplicate-items-from-nested-list?rq=1 –

回答

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()b_li这使得查找更快。
  • s转换为一个元组,因为不需要将唯一的第一个和第三个元素存储为列表。
  • 减少功能查找,加快代码。
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]] 

加成

此外,在想着告诉变量的名称通常也花时间花。通常情况下,最初的解决方案比预期的要长得多。

+0

+1这是一个简单,干净的解决方案。 –

+0

谢谢,这是一个巨大的飞跃:) –

0

这是一个基于@ iurisilvio的iterator评论并与来自其他人的set为基础的解决方案结合使用itertools.compress的解决方案。 而不是从输入列表中的元素构建output_list,包含布尔值的selector列表是相对于输入列表中的元素建立的。值为True表示输入列表中的相应元素应保留在输出中。然后可以通过itertools.compressselector应用于输入列表以产生可迭代的输出。

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] 
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]]