使用部分列在Python中去除重复项
我有一个用制表符分隔的输入文件 input.txt,内容如下:
A B C
A B D
E F G
E F T
E F K
这些数据是用制表符分开的。
我想要删除重复的行,但只有当多行的第一列和第二列相同时才删除。
所以,即使第一行和第二行的第三列不同,只要它们的第一列和第二列相同,我就想删除后面出现的那一行,比如 "A B D"。
所以,输出文件 output.txt 应该是这样的:
A B C
E F G
如果我想用普通的方法去掉重复项,我只需要把列表变成一个“集合”(set),这样就可以了。
但现在我想用“某些”列来去重。
在 Excel 中,这个操作非常简单。
数据 -> 删除重复项 -> 选择列
在 MatLab 中也很简单。
导入 input.txt -> 使用“unique”函数针对第一列和第二列 -> 删除编号为“1”的行
但是在 Python 中,我找不到怎么做,因为我只知道用“set”来去重。
===========================
这是我根据 undefined_is_not_a_function 的回答进行的实验。
我不确定怎么把结果覆盖到 output.txt,也不知道怎么修改代码来让我指定用于去重的列(比如第三列和第五列)。
import sys
input = sys.argv[1]
seen = set()
data = []
for line in input.splitlines():
key = tuple(line.split(None, 2)[0])
if key not in seen:
data.append(line)
seen.add(key)
5 个回答
请注意,我不是专家,但我还是有一些想法可能对你有帮助。
有一个叫做csv的模块专门用来处理csv文件,你可以去看看,或许会有一些有趣的东西。
首先,我想问问你是怎么存储这些数据的?是用列表吗?
像这样:
[[A,B,C],
[A,B,D],
[E,F,G],...]
这可能是合适的选择。(也许不是最好的选择)
其次,能否遍历整个列表呢?
你可以简单地存储一行,然后把它和所有行进行比较。
我会这样做:假设列表里包含字母。
copy = list
index_list = []
for i in range(0, len(list)-1):
for j in range(0, len(list)-1): #and exclude i of course
if copy[i][1] == list[j][1] and copy[i][0] == list[j][0] and i!=j:
index_list.append(j)
for i in index_list: #just loop over the index list and remove
list.pop(index_list[i])
这不是有效的代码,但它给你提供了一个思路。这是完成你任务的最简单方法,可能不是最合适的选择。(而且这会花费一些时间,因为你需要进行平方数量的操作)。
补充一下:用pop,而不是remove。
假设你已经读取了你的对象,并且你有一个叫做 rows 的数组(如果你需要帮助可以告诉我),下面的代码应该可以正常运行:
entries = set()
keys = set()
for row in rows:
key = (row[0], row[1]) # Only the first two columns
if key not in keys:
keys.add(key)
entries.add((row[0], row[1], row[2]))
从下面的代码,你可以做到这一点。
file_ = open('yourfile.txt')
lst = []
for each_line in file_ .read().split('\n'):
li = each_line .split()
lst.append(li)
dic = {}
for l in lst:
if (l[0], l[1]) not in dic:
dic[(l[0], l[1])] = l[2]
print dic
抱歉,变量名可能不太好理解。
如果你能使用Unix系统,里面有一个叫做sort的工具,非常适合解决你的问题。
sort -u -t$'\t' --key=1,2 filein.txt
我知道这是一个关于Python的问题,但有时候Python并不是解决这个问题的最佳工具。而且你总是可以在你的Python脚本中调用系统命令。
你应该使用 itertools.groupby
来处理这个问题。在这里,我是根据前两列的数据进行分组,然后用 next()
来获取每个组的第一个项目。
>>> from itertools import groupby
>>> s = '''A B C
A B D
E F G
E F T
E F K'''
>>> for k, g in groupby(s.splitlines(), key=lambda x:x.split()[:2]):
print next(g)
...
A B C
E F G
如果输入数据来自文件,只需把 s.splitlines()
替换成文件对象就可以了。
请注意,上面的解决方案只有在数据按照前两列排序的情况下才有效。如果数据没有排序,那么你需要在这里使用 set
。
>>> from operator import itemgetter
>>> ig = itemgetter(0, 1) #Pass any column number you want, note that indexing starts at 0
>>> s = '''A B C
A B D
E F G
E F T
E F K
A B F'''
>>> seen = set()
>>> data = []
>>> for line in s.splitlines():
... key = ig(line.split())
... if key not in seen:
... data.append(line)
... seen.add(key)
...
>>> data
['A B C', 'E F G']