使用grep或python比较大文件

时间:2017-08-07 18:39:39

标签: python linux bash

我有两个网址列表,我想知道新的字符串。例如:

listA.txt
string1
string2

listB.txt
string1
string3

然后我比较两个列表,以了解列表B中的新字符串:

grep -w -f listA.txt -v listB.txt

cat listA.txt | grep -Fxvf - listB.txt

最终结果:

string3

问题是我有数百万字符串,因此运行该命令会占用我PC的所有资源并崩溃。

有没有办法用python(它消耗更少的资源并且更快)

感谢

4 个答案:

答案 0 :(得分:0)

此方法从第一个文件(listA)创建一个集合。唯一的内存要求是足够的空间来容纳这个集合。然后它遍历listB.txt文件中的每个URL(内存效率非常高)。如果url不在此集合中,则会将其写入新文件(也非常高效)。

filename_1 = 'listA.txt'
filename_2 = 'listB.txt'
filename_3 = 'listC.txt'
with open(filename_1, 'r') as f1, open(filename_2, 'r') as f2, open(filename_3, 'w') as fout:
    s = set(val.strip() for val in f1.readlines())
    for row in f2:
        row = row.strip()
        if row not in s:
            fout.write(row + '\n')

答案 1 :(得分:0)

如果您有足够的内存,请将文件读入两个列表。然后将列表转换为集合,即setA = set(listA),然后您可以使用Python集可用的各种运算符来执行您喜欢的任何操作,例如setA - setB

我以前使用它并且非常有效。

答案 2 :(得分:0)

您需要按照此处的解决方案进行操作:

Get difference between two lists

但首先,您需要知道如何将文件加载到列表中,该列表位于:

How do I read a file line-by-line into a list?

祝你好运。所以像这样:

SELECT *,
      sum(total_count) over(partition by pilot_ind) As total_per_pilot_ind,
      round(100.0 * total_count / sum(total_count) over(partition by pilot_ind) ,1)
        as pct_pilot_ind_total
FROM (
select 
    r.pilot_ind
    ,r.last_form_step_completed
    ,count(*) total_count
from
    results r
group by
    r.pilot_ind
    ,r.last_form_step_completed
) x
order by 1,2

答案 3 :(得分:0)

如果你甚至无法将较小的文件放入内存中,那么Python也无济于事。通常的解决方案是对输入进行排序并使用一次只对三个条目进行操作的算法(它从一个文件读取一个条目,从另一个文件读取一个条目,然后根据它们的排序顺序决定从下一个文件读取哪个文件。需要在任何时候将其中三个保留在内存中以决定在代码中采用哪个分支。)

如果GNU sort无法将内容放入内存中,那么它将回退到基于磁盘的合并排序,因此它基本上只受可用临时磁盘空间的限制。

#!/bin/sh
export LC_ALL=C # use trad POSIX sort order
t=$(mktemp -t listA.XXXXXXXX) || exit 123
trap 'rm -f $t' EXIT HUP INT
sort listA.txt >"$t"
sort listB.txt | comm -12 "$t" -

如果输入文件已经排序,显然只需要comm

Bash(我猜可能也是Zsh和ksh)提供了像comm <(sort listA.txt) <(sort listB.txt)这样的进程替换,但我不确定在内存耗尽时这是否很强大。

我确信您已经发现,如果文件的大小完全不同,无论您的方法如何,都要将较小的文件保留在内存中(因此切换listA.txt和{{1如果listB.txt是较小的一个,在这里和原始的listB.txt命令行中;虽然我想这里会产生较小的差异。)