【问题标题】:sort and get uniq lines of file in python在python中排序并获取uniq文件行
【发布时间】:2013-11-04 09:19:58
【问题描述】:

我总是使用这个命令行来排序和只获取 uniq 行,即使是大文件(超过 500,000 行),它也可以作为一种魅力

sort filename.txt | uniq | sponge filename.txt

最短的等效python代码是

f = open("filename.txt", "r")
lines = [line for line in f]
lines = lines.sort()
lines = set(lines)

但是由于内存限制,这当然是不可扩展的,并且在 python 中编写可扩展的代码需要时间 ,所以我想知道python中最短的等效代码(包)是什么

【问题讨论】:

  • sort 在对大文件进行排序时会创建临时文件来保存中间结果,因此并不是那么简单。为什么要重新发明轮子?
  • sort 调用之前应用set,这将减少NlogN 中的N
  • @HadyElsahar:我很困惑。如果不想重新发明轮子,为什么要在 Python 中重写sort | uniq
  • @HadyElsahar:调用外部命令没有错。如果您不想将结果写入文件,请从进程的标准输出中读取(尽管如果它的写入速度快于您的读取速度,您可能会遇到缓冲问题)。 sortuniq 是可移植的,运行速度比任何纯 Python 代码都要快。
  • @HadyElsahar:有些模块会包装 subprocess 以使其更漂亮,如果这让您望而却步:amoffat.github.io/sh

标签: python command-line unique


【解决方案1】:

您不需要在 python 中进行排序,因为 set 即使不排序也会处理唯一性。

f = open("filename.txt", "r")
lines = set(f.readlines())

shell sort 命令还将这些行加载到内存中,因此使用它不会为您节省任何内存。如果你有非常大的文件或者你坚持不使用额外的内存,你可以尝试一些疯狂的技巧,就像这里展示的那样:http://neopythonic.blogspot.in/2008/10/sorting-million-32-bit-integers-in-2mb.html

【讨论】:

  • 写入文件需要先将所有文件加载到内存中,这就是我想要跳过的,还要编写额外的代码来处理这个
  • 即使您使用 shell sort,它也会将这些行加载到内存中。所以在这方面使用 shell 对你没有帮助。上述解决方案将使用比 shell 中的 sort 更少的内存。因此,在从 python 调用 sort | uniq 和使用上述代码之间进行选择时,您应该尝试在 python 中执行此操作,因为 shell 没有任何优势。
  • @HariShankar: sort 不需要将所有内容都存储在内存中(它可能会使用临时文件)
【解决方案2】:

有一个迭代器可以完成 sort 的工作,即 sorted。让我们制作一个模仿 uniq 的,只产生不等于前一行的行:

def uniq(iterator):
    previous = float("NaN")  # Not equal to anything
    for value in iterator:
        if previous != value:
            yield value
            previous = value

现在你可以做同样的事情了:

with open('/path/to/filename') as f:
    for line in uniq(sorted(f)):
        print(line)

BUt 排序(和 shell 的排序)无论如何都必须存储所有内容(如果文件中的最后一行应该首先输出怎么办),所以它比只使用 set(f) 而不是 uniq(sorted(f)) 更糟糕。

【讨论】:

  • 你可以使用itertools模块来实现uniq = lambda it: imap(itemgetter(0), groupby(it))sort 不需要将所有内容都存储在内存中(它可能会使用临时文件)。要支持大型输入文件,请参阅Sorting text file by using Python
【解决方案3】:

使用来自 python 的 shell 命令:

import os
os.system("sort filename.txt | uniq | sponge filename.txt")

【讨论】:

    【解决方案4】:

    下面是一个简短的例子:

    with open("filename.txt", 'r') as f:
        lines = set(f)
    

    另外,应该注意的一件事是,在这种情况下,一次只有一行会被加载到内存中。原因是上面的代码等价于:

    lines = set()
    f = open("filename.txt", 'r')
    for line in f: # now f works as a generator of lines, reading only one line at a time
         lines.add(line)
    

    【讨论】:

    • 但最终lines set 将包含从文件到内存中的所有唯一行。
    • 这比在内存中加载所有行要好,除非所有行都是唯一的。
    猜你喜欢
    • 2011-09-13
    • 1970-01-01
    • 2015-10-10
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 2013-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多