V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
daiqiangbudainiu
V2EX  ›  Python

如果有 33W 行文字,去重应该怎么写呢?

  •  
  •   daiqiangbudainiu · Dec 17, 2017 · 6993 views
    This topic created in 3060 days ago, the information mentioned may be changed or developed.

    比如有个 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)
    

    代码渣,请轻喷

    44 replies    2017-12-20 21:07:00 +08:00
    l00t
        1
    l00t  
       Dec 17, 2017
    为啥不用 dict
    realpg
        2
    realpg  
    PRO
       Dec 17, 2017   ❤️ 1
    33 万行 这么点数据还考虑啥性能……
    wspsxing
        3
    wspsxing  
       Dec 17, 2017
    hash
    ihciah
        4
    ihciah  
       Dec 17, 2017 via iPhone
    list 查找是线性的似乎…换成 dict 或者 set 会好
    fy
        5
    fy  
       Dec 17, 2017
    蛐蛐 33w 行,pandas 读入,drop_duplicates,导出,收工。
    vimiix
        6
    vimiix  
       Dec 17, 2017
    我的话,可能会先考虑用集合 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()

    仅供参考,没试验过。
    Guaidaodl
        7
    Guaidaodl  
       Dec 17, 2017
    list 的查找是 O(n) 的吧,整个复杂度是 O(n^2)。去重的时候不要用 list, 换成 set 就好了。
    em70
        8
    em70  
       Dec 17, 2017   ❤️ 1
    直接 EmEditor 打开 TXT,工具->插件->删除重复行,搞定
    rrfeng
        9
    rrfeng  
       Dec 17, 2017   ❤️ 11
    这个题我最喜欢了:

    awk '!a[$0]++' file.txt
    ytterbium
        10
    ytterbium  
       Dec 17, 2017 via Android
    这么小数据量,hash, map 都行啊。linux 的话就直接 sort -u,虽然不是最快的,不过简单省心。
    ytterbium
        11
    ytterbium  
       Dec 17, 2017 via Android
    @ytterbium 之前做 nlp 数据预处理去重过 5 亿多行的数据,偷懒用的 sort -u,多线程 1 天不到也就跑完了。30 几万行几秒的事。
    param
        12
    param  
       Dec 17, 2017 via Android
    转成 set 再转成 list 不知道行不行
    ytterbium
        13
    ytterbium  
       Dec 17, 2017 via Android
    @ytterbium 50 亿
    param
        14
    param  
       Dec 17, 2017 via Android
    list(set(open('/Users/lizhao/Downloads/aboutchinese.dict.yaml'))) 这样子?不知道性能如何。
    cljnnn
        15
    cljnnn  
       Dec 17, 2017 via Android
    用 set,set 自带去重
    ioven
        16
    ioven  
       Dec 17, 2017
    如果对流程没太多需要直接用 awk 更简单
    swulling
        17
    swulling  
       Dec 17, 2017 via iPhone
    awk dict
    wweir
        18
    wweir  
       Dec 17, 2017 via iPhone
    除了 hash,还可以考虑用排序的方法来做
    如果 33w 仅仅是代表大(内存不允许)的话,还可以考虑利用一些磁盘排序的算法
    secsilm
        19
    secsilm  
       Dec 17, 2017 via Android
    这也不大吧
    cxbig
        20
    cxbig  
       Dec 17, 2017
    sort -u dict.yml
    awk '!a[$0]++' dict.yml
    ceclinux
        21
    ceclinux  
       Dec 17, 2017 via Android
    要是对结果没有顺序要求的,不要想太多,直接 sort 然后 uniq 即可
    fyibmsd
        22
    fyibmsd  
       Dec 17, 2017
    cat old | uniq | tee new
    artandlol
        23
    artandlol  
       Dec 17, 2017   ❤️ 3
    一个 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
    ericls
        24
    ericls  
       Dec 17, 2017   ❤️ 1
    from collections import OrderedDict
    '\n'.join(OrderedDict.fromkeys(string.splitlines()))
    selfAccomplish
        25
    selfAccomplish  
       Dec 17, 2017 via Android
    如果楼主的数据是在 window 下面呢,没有 linux 的机子或者数据量大拷不进 linux 的虚拟机。
    cdwyd
        26
    cdwyd  
       Dec 17, 2017 via Android
    list(set(f.readlines()))
    takeoffyoung
        27
    takeoffyoung  
       Dec 17, 2017
    cat xxx.txt | sort | uniq 这样??
    msg7086
        28
    msg7086  
       Dec 17, 2017
    @selfAccomplish 那就在 Windows 下用 awk 啊。
    eycfsjd
        29
    eycfsjd  
       Dec 17, 2017
    1、for i in f.readlines() 改成 for i in f: 是不是更好;
    2、查重用 dict 性能好,如果每一行都比较长 建议把 line 换算一下再 put 到 dict 中,要保证顺序就 orderdict
    young6
        30
    young6  
       Dec 17, 2017 via Android
    要是对行顺序没要求,用 cat,sort,uniq 吧,还写啥代码啊。要是行顺序要求不变,python 有有序字典
    leavic
        31
    leavic  
       Dec 17, 2017
    有序字典吧,set 虽然可以去重,但你恢复的时候就无序了。
    wizardoz
        32
    wizardoz  
       Dec 17, 2017
    dict 可破,用文本当 key,用行号当 value
    dict 在判断 in 的时候效率应该吊打 list。
    jyf007
        33
    jyf007  
       Dec 17, 2017
    @msg7086
    @artandlol
    @young6
    @selfAccomplish
    @swulling
    @ioven
    @rrfeng

    别忘了用这个 https://frippery.org/busybox/
    ,开一个批处理写成 busybox ash 就有坠吼的环境了,(其实没什么大功能)
    我原来写了一个在 windows 处理 netstat 输出的就是这么骚操作.
    artandlol
        34
    artandlol  
       Dec 17, 2017 via iPhone
    @jyf007
    cmder
    +gow
    或者用在线 docker-ce 再通过用 websocket 映射到浏览器
    估计你要百度一晚上了
    jyf007
        35
    jyf007  
       Dec 17, 2017
    @artandlol 说起来 unix 的好还是只能体现在 busybox 上了,其他不能算是原始的 unix 了
    我当时是直接操作 cmd 的窗口就这 vi 写脚本,或者开记事本搞,
    完整的 msys2 我装完有 45G 这么大,不够轻盈,
    我觉得安利 unix 必须提 busybox 和 dropbear.
    daiqiangbudainiu
        36
    daiqiangbudainiu  
    OP
       Dec 17, 2017
    @wizardoz

    能给个示例吗?我不知道该怎么用 dict 去重
    ipwx
        37
    ipwx  
       Dec 17, 2017
    24L 是 Python 最优雅的解决方案。
    Lpl
        38
    Lpl  
       Dec 17, 2017
    vim 文件

    然后 :sort u
    会先排序然后取相同行第一行
    lylijincheng
        39
    lylijincheng  
       Dec 18, 2017
    ```
    Array.from(new Set(longlongtext.split(''))).join('')
    ```
    wizardoz
        40
    wizardoz  
       Dec 18, 2017
    @warcraft1236 把你的 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 排序,保持原来顺序
    ...
    daiqiangbudainiu
        41
    daiqiangbudainiu  
    OP
       Dec 18, 2017
    @wizardoz
    多谢,不过再问一个基础的问题,怎么根据 dict 的 values 排序写入文件呢?
    araraloren
        42
    araraloren  
       Dec 18, 2017
    .say for f.lines.unique(:with(&[eqv])) (in Perl6, f is IO::Handle)
    wizardoz
        43
    wizardoz  
       Dec 18, 2017
    @warcraft1236
    # 排序并丢弃行号信息,得到的是按照原本顺序的文本数据
    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)
    shawndev
        44
    shawndev  
       Dec 20, 2017
    cat file | uniq
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   808 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 141ms · UTC 22:29 · PVG 06:29 · LAX 15:29 · JFK 18:29
    ♥ Do have faith in what you're doing.