Python中如果有33W行文字,如何进行高效去重?

比如有个 txt 文本,一共有 33W 行文字,以行作为单位,去重,我应该怎么写效率会比较高呢?

我目前用的普通的方法,发现耗时比较长

我列出我目前的方法

    with open('/Users/lizhao/Downloads/aboutchinese.dict.yaml') as f:
    for i in f.readlines():
        if i == '\n':
            continue
        if i not in oldList:
            oldList.append(i)

with open('tmp.txt','w') as g:
    g.writelines(oldList)

代码渣,请轻喷


Python中如果有33W行文字,如何进行高效去重?

41 回复

为啥不用 dict


直接上代码,用生成器配合集合来搞,内存占用小,速度也快。

def deduplicate_large_file(input_file_path, output_file_path):
    """
    对大文件进行逐行去重
    :param input_file_path: 输入文件路径
    :param output_file_path: 输出文件路径
    """
    seen = set()
    
    with open(input_file_path, 'r', encoding='utf-8') as infile, \
         open(output_file_path, 'w', encoding='utf-8') as outfile:
        
        for line in infile:
            # 去除行尾换行符,避免换行符差异导致去重失败
            cleaned_line = line.rstrip('\n')
            
            if cleaned_line not in seen:
                seen.add(cleaned_line)
                outfile.write(line)  # 写入原始行,保留原始换行符

# 使用示例
if __name__ == "__main__":
    input_file = "your_330k_lines.txt"  # 替换为你的输入文件路径
    output_file = "deduplicated_output.txt"  # 替换为你的输出文件路径
    
    deduplicate_large_file(input_file, output_file)
    print(f"去重完成!原始文件: {input_file}, 输出文件: {output_file}")

关键点解析:

  1. 生成器逐行读取for line in infile 一次只读一行到内存,33万行完全没问题。
  2. 集合查重seen = set() 用哈希表实现O(1)时间复杂度的查找,比列表快几个数量级。
  3. 内存优化:只存储字符串内容(cleaned_line),不存整行,进一步节省内存。
  4. 保留格式outfile.write(line) 写入原始行,保持原有换行符格式。

如果文件更大(比如上亿行),可以考虑分块处理或者用布隆过滤器,但33万行这个方案绰绰有余。

一句话建议:用集合+生成器逐行处理,兼顾速度和内存。

list 查找是线性的似乎…换成 dict 或者 set 会好

我的话,可能会先考虑用集合 set,下面是伪代码思路:
values = set()
vals_len = 0

dest_file = open(‘dest_file’, ‘w’)
with open txt:
for line in readlines():
val = hash(line)
vals_len = len(values)
values.add(val) #主要在这一步借助 set 的不重复特性,判断集合长度是否增长
if len(values) == vals_len+1:
dest_file.write(line)
dest.file.close()

仅供参考,没试验过。

list 的查找是 O(n) 的吧,整个复杂度是 O(n^2)。去重的时候不要用 list, 换成 set 就好了。

这个题我最喜欢了:

awk ‘!a[$0]++’ file.txt

这么小数据量,hash, map 都行啊。linux 的话就直接 sort -u,虽然不是最快的,不过简单省心。

之前做 nlp 数据预处理去重过 5 亿多行的数据,偷懒用的 sort -u,多线程 1 天不到也就跑完了。30 几万行几秒的事。

转成 set 再转成 list 不知道行不行

用 set,set 自带去重

如果对流程没太多需要直接用 awk 更简单

除了 hash,还可以考虑用排序的方法来做
如果 33w 仅仅是代表大(内存不允许)的话,还可以考虑利用一些磁盘排序的算法

这也不大吧

sort -u dict.yml
awk ‘!a[$0]++’ dict.yml

要是对结果没有顺序要求的,不要想太多,直接 sort 然后 uniq 即可

cat old | uniq | tee new

一个 uniq 也能发一贴
root@x:~# cat test
247
214
209
228
216
216
root@x:~# cat test|uniq
247
214
209
228
216
root@x:~# cat test|sort -u
209
214
216
228
247
root@x:~# cat test|awk '!a[$0]++'
247
214
209
228
216

from collections import OrderedDict
’\n’.join(OrderedDict.fromkeys(string.splitlines()))

如果楼主的数据是在 window 下面呢,没有 linux 的机子或者数据量大拷不进 linux 的虚拟机。

list(set(f.readlines()))

cat xxx.txt | sort | uniq 这样??

那就在 Windows 下用 awk 啊。

1、for i in f.readlines() 改成 for i in f: 是不是更好;
2、查重用 dict 性能好,如果每一行都比较长 建议把 line 换算一下再 put 到 dict 中,要保证顺序就 orderdict

要是对行顺序没要求,用 cat,sort,uniq 吧,还写啥代码啊。要是行顺序要求不变,python 有有序字典

有序字典吧,set 虽然可以去重,但你恢复的时候就无序了。

dict 可破,用文本当 key,用行号当 value
dict 在判断 in 的时候效率应该吊打 list。









别忘了用这个 https://frippery.org/busybox/
,开一个批处理写成 busybox ash 就有坠吼的环境了,(其实没什么大功能)
我原来写了一个在 windows 处理 netstat 输出的就是这么骚操作.


cmder
+gow
或者用在线 docker-ce 再通过用 websocket 映射到浏览器
估计你要百度一晚上了

说起来 unix 的好还是只能体现在 busybox 上了,其他不能算是原始的 unix 了
我当时是直接操作 cmd 的窗口就这 vi 写脚本,或者开记事本搞,
完整的 msys2 我装完有 45G 这么大,不够轻盈,
我觉得安利 unix 必须提 busybox 和 dropbear.



能给个示例吗?我不知道该怎么用 dict 去重

24L 是 Python 最优雅的解决方案。

vim 文件

然后 :sort u
会先排序然后取相同行第一行

<br>Array.from(new Set(longlongtext.split(''))).join('')<br>

把你的 list 换成 dict 就可以了!

buffer = {}
sort_key = 0
with open(‘file.txt’, ‘r’) as fp:
for line in fp.readlines():
if line not in buffer:
sort_key += 1
buffer[line] = sort_key


# 完了用 sort_key 排序,保持原来顺序


多谢,不过再问一个基础的问题,怎么根据 dict 的 values 排序写入文件呢?

.say for f.lines.unique(:with(&[eqv])) (in Perl6, f is IO::Handle)


# 排序并丢弃行号信息,得到的是按照原本顺序的文本数据
sorted_lines = sorted([item[0] for item in buffer.items()], cmp=lambda a, b: a[1] - b[1])

# 输出
with open(“output.txt”, “w”) as fp:
for line in sorted_lines:
print(line, file=fp)

cat file | uniq

回到顶部