根据每个子列表的第三项去除重复项
我有一个列表,里面又包含了很多小列表,长得像这样:
c = [['470', '4189.0', 'asdfgw', 'fds'],
['470', '4189.0', 'qwer', 'fds'],
['470', '4189.0', 'qwer', 'dsfs fdv']
...]
这个列表大约有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分钟,然后就停止了。我觉得这个程序不应该花这么长时间,所以我猜我的逻辑可能有问题。
我感觉创建一个全新的列表来存放这些小列表可能不是个好主意。任何帮助都非常感谢,欢迎大家挑剔,因为我还在学习。如果我的用词不对,也请帮我纠正。
3 个回答
使用pandas库。我猜你有更好的列名。
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
你的代码里有一个很明显的逻辑错误:
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)
我会这样做:
seen = set()
cond = [x for x in c if x[3] not in seen and not seen.add(x[3])]
解释:
seen
是一个集合,用来记录每个子列表中已经遇到的第四个元素。cond
是压缩后的列表。如果 x[3]
(其中 x
是 c
中的一个子列表)不在 seen
中,那么 x
会被添加到 cond
中,同时 x[3]
也会被添加到 seen
中。
seen.add(x[3])
会返回 None
,所以 not seen.add(x[3])
总是会是 True
,不过这一部分只有在 x[3] not in seen
为 True
的时候才会被判断,因为 Python 会使用短路评估。如果第二个条件被判断,它总是会返回 True
,并且会有一个副作用,就是把 x[3]
加入到 seen
中。这里还有一个例子说明发生了什么(print
返回 None
,并且有一个“副作用”,就是打印出一些东西):
>>> False and not print('hi')
False
>>> True and not print('hi')
hi
True