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行文字,如何进行高效去重?
为啥不用 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}")
关键点解析:
- 生成器逐行读取:
for line in infile一次只读一行到内存,33万行完全没问题。 - 集合查重:
seen = set()用哈希表实现O(1)时间复杂度的查找,比列表快几个数量级。 - 内存优化:只存储字符串内容(cleaned_line),不存整行,进一步节省内存。
- 保留格式:
outfile.write(line)写入原始行,保持原有换行符格式。
如果文件更大(比如上亿行),可以考虑分块处理或者用布隆过滤器,但33万行这个方案绰绰有余。
一句话建议:用集合+生成器逐行处理,兼顾速度和内存。
hash
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 不知道行不行
50 亿
用 set,set 自带去重
如果对流程没太多需要直接用 awk 更简单
awk dict
除了 hash,还可以考虑用排序的方法来做
如果 33w 仅仅是代表大(内存不允许)的话,还可以考虑利用一些磁盘排序的算法
这也不大吧
sort -u dict.yml
awk ‘!a[$0]++’ dict.yml
要是对结果没有顺序要求的,不要想太多,直接 sort 然后 uniq 即可
cat old | uniq | tee new
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

