处理大文件 - python或命令行的建议?

Dar*_*ick 2 python command-line parsing

给定两个文件,一个包含表单的条目:

label1 label2 name1
label1 label3 name2
Run Code Online (Sandbox Code Playgroud)

和另一个形式:

label1 label2 name1 0.1 1000
label9 label6 name7 0.8 0.5
Run Code Online (Sandbox Code Playgroud)

假设你想从文件二中提取那些前三个元素出现在文件一行中的那些行(重要的顺序) - 任何有关如何快速填充的建议?

给定上述示例数据的任何此类脚本的输出文件将是:

label1 label2 name1 0.1 1000
Run Code Online (Sandbox Code Playgroud)

我玩弄python:

inp = open(file1.txt, 'r')
look_up = [i.split() for i in inp.readlines()]
inp.close()

inp = open('file2', 'wt')

holder = []

line = inp.readline()
while line:
    line = line.split()
    if [line[0], line[1], line[2]] in look_up:
        holder.append(line)
    line = inp.readline()
Run Code Online (Sandbox Code Playgroud)

然而,这似乎需要一段时间.这些文件相当大.

谢谢!

Joe*_*ton 8

你的python版本是相当低效的,因为你正在测试列表中的成员资格,而不是集合或字典(即O(n)查找时间而不是O(1)).

尝试使用set元组或set字符串代替.元组是一个更好的选择,因为这两个文件可以分成不同的分隔符,但我认为你不会看到特别大的性能差异.tuple('something'.split())与测试很长列表的成员资格相比,它相对较快.

此外,没有必要打电话inp.readlines().换句话说,你可以做到

look_up = set(tuple(line.split()) for line in inp)
Run Code Online (Sandbox Code Playgroud)

并且您应该看到显着的加速,而不必更改代码的任何其他部分tuple(line[:3])而不是[line[0], line[1], line[2]].

实际上,grep和bash对于这个来说非常完美......(未经测试,但它应该可以工作.)

while read line
do
    grep "$line" "file2.txt"
done < "file1.txt"
Run Code Online (Sandbox Code Playgroud)

要查看哪一个更快,我们可以生成一些测试数据(大约4500个键file1.txt和1000000行file2.txt),并对同一个东西的简单python版本进行基准测试(大致......这些行将以不同于grep的顺序打印版.).

with open('file1.txt', 'r') as keyfile:
    lookup = set(tuple(line.split()) for line in keyfile)

with open('file2.txt', 'r') as datafile:
    for line in datafile:
        if tuple(line.split()[:3]) in lookup:
            print line,
Run Code Online (Sandbox Code Playgroud)

python版本的速度提高了约70倍:

jofer@cornbread:~/so> time sh so_temp149.sh > a

real    1m47.617s
user    0m51.199s
sys     0m54.391s
Run Code Online (Sandbox Code Playgroud)

jofer@cornbread:~/so> time python so_temp149.py > b

real    0m1.631s
user    0m1.558s
sys     0m0.071s
Run Code Online (Sandbox Code Playgroud)

当然,这两个例子正以完全不同的方式解决问题.我们真的在比较两种算法,而不是两种算法.例如,如果我们只有几个关键行file1,bash/grep解决方案很容易获胜.

(bash有一个内置的容器,有O(1)查找成员资格吗?(我认为bash 4可能有一个哈希表,但我对它一无所知......)尝试实现它会很有趣与bash中上面的python示例类似的算法,以及...)

  • 你不能拥有一组列表.每个`set`元素都必须是可清除的(完全不可变的). (2认同)