【问题标题】:Remove duplicates in a list of lists based on the third item in each sublist根据每个子列表中的第三项删除列表列表中的重复项
【发布时间】:2014-08-09 08:10:56
【问题描述】:

我有一个看起来像这样的列表:

c = [['470', '4189.0', 'asdfgw', 'fds'],
     ['470', '4189.0', 'qwer', 'fds'],
     ['470', '4189.0', 'qwer', 'dsfs fdv'] 
      ...]

c 有大约 30,000 个内部列表。我想做的是根据每个内部列表中的第 4 项消除重复项。所以上面的列表看起来像:

c = [['470', '4189.0', 'asdfgw', 'fds'],['470', '4189.0', 'qwer', 'dsfs fdv'] ...]

这是我目前所拥有的:

d = [] #list that will contain condensed c
d.append(c[0]) #append first element, so I can compare lists
for bact in c: #c is my list of lists with 30,000 interior list
    for items in d:
        if bact[3] != items[3]:
            d.append(bact)  

我认为这应该可行,但它只是运行和运行。我让它运行了 30 分钟,然后杀死了它。我不认为程序应该花这么长时间,所以我猜我的逻辑有问题。

我觉得创建一个全新的列表非常愚蠢。任何帮助将不胜感激,请在我学习时随时挑剔。如果我的词汇不正确,请更正我的词汇。

【问题讨论】:

  • 您如何知道哪些重复项需要删除?
  • 您是否考虑过输出中已经存在的第四个元素的单独set?这将使成员资格查找更快。
  • 你是对的。我想我目前不需要其他信息。你可以直接创建一个'set',还是我遍历我的列表创建一个列表,然后调用set函数?
  • @user3754225 你可以add 去设置,不要重复c 两次!
  • 你应该看看熊猫。如果(我假设)这不会是您对这些数据执行的最后一个类似表的操作,那么 pandas 将是一项非常好的投资。而你在 pandas 中的操作只是df.drop_duplicates('col_4')

标签: python duplicate-removal nested-lists


【解决方案1】:

我会这样做:

seen = set()
cond = [x for x in c if x[3] not in seen and not seen.add(x[3])]

解释:

seen 是一个跟踪每个子列表中已经遇到的第四个元素的集合。 cond 是精简列表。如果x[3](其中xc 中的子列表)不在seen 中,则x 将被添加到condx[3] 将被添加到seen

seen.add(x[3]) 将返回None,因此not seen.add(x[3]) 将始终为True,但仅当x[3] not in seenTrue 时才会评估该部分,因为Python 使用短路评估。如果第二个条件得到评估,它将始终返回True,并具有将x[3] 添加到seen 的副作用。这是正在发生的另一个例子(print 返回None 并具有打印某些东西的“副作用”):

>>> False and not print('hi')
False
>>> True and not print('hi')
hi
True

【讨论】:

  • 我对“而不是”感到困惑。这是 if blah then blah 的逻辑等价物吗?还是完全是别的东西?
  • @user3754225 我稍微扩展了解释
【解决方案2】:

使用熊猫。我假设您也有更好的列名。

c = [['470', '4189.0', 'asdfgw', 'fds'],
     ['470', '4189.0', 'qwer', 'fds'],
     ['470', '4189.0', 'qwer', 'dsfs fdv']]
import pandas as pd
df = pd.DataFrame(c, columns=['col_1', 'col_2', 'col_3', 'col_4'])
df.drop_duplicates('col_4', inplace=True)
print df

  col_1   col_2   col_3     col_4
0   470  4189.0  asdfgw       fds
2   470  4189.0    qwer  dsfs fdv

【讨论】:

    【解决方案3】:

    您当前的代码中存在严重的逻辑缺陷:

    for items in d:
        if bact[3] != items[3]:
            d.append(bact)  
    

    这会将bact 添加到d d 中不匹配的每个项目添加一次。对于最小的修复,您需要切换到:

    for items in d:
        if bact[3] == items[3]:
            break
    else:
        d.append(bact)  
    

    如果d 中的所有 项不匹配,则添加一次bact。我怀疑这将意味着您的代码在更合理的时间内运行。


    最重要的是,一个明显的性能改进(速度提升,尽管以内存使用为代价)是保持您目前看到的第四个元素的set。集合上的查找使用哈希,因此成员资格测试(突出显示)会更快。

    d = []
    seen = set()
    for bact in c:
        if bact[3] not in seen: # membership test
            seen.add(bact[3])
            d.append(bact)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-14
      • 1970-01-01
      • 1970-01-01
      • 2020-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多