有效地将特定行复制到另一个文件(Python 3.3)

时间:2013-06-05 14:52:56

标签: python

如何在Python中将所有偶数行从一个文件复制到新文件?

当我想要从一个文件复制到另一个文件的非常精确的行数时,偶数只是一个例子,但它应该是一个很好的例子。

我使用它,但效率非常低(大约需要5分钟):

# foo.txt holds 200,000 lines with 300 values
list = [0, 2, 4, 6, 8, 10..... 199996, 199998]
newfile = open(savefile, "w")
with open("foo.txt", "r") as file:
    for i, line in enumerate(file):
        if i in list:
            newfile.write(line)
newfile.close()

如果能解释为什么这么慢,我也会很感激:逐行阅读(大约15秒),并且手册也会建议。

编辑:我的道歉;我不是在寻找具体的奇数/偶数例子;它仅仅是为了解决如何处理200k值中的大约100k而不是简单的顺序。除了找到更有效的方法来处理奇数/偶数之外,这里的I / O问题没有通用解决方案吗?再次为此提出道歉。

4 个答案:

答案 0 :(得分:2)

一直在寻找的是list。为了确定i是否在list中,它必须扫描整个列表以确保它不存在。如果你真的只关心偶数,你可以简单地使用if i % 2 == 0,但如果你有一组特定的行号,你应该使用set,它有O(1)成员资格测试,例如

keep = {1, 5, 888, 20203} 

然后

if i in keep:

答案 1 :(得分:1)

你花费了大量的时间创作,然后反复搜索(在每一行!!!)那个怪异的list。只需逐行读取第一个文件并跳过其他文件。您可以使用切换标记执行此操作,或者只检查行号是否可以被2整除(在我看来更清晰)。

for i, line in enumerate(file):
    if i % 2 == 0:
        newfile.write(line)

编辑以回复您的修改:您的问题现在是“如何从文件中复制任意行?”这很大程度上取决于如何定义这些任意行。答案仍然是来使用“通缉”行号列表,因为搜索该列表需要很长时间,而且您必须在每一行搜索它。

如果目标本质上是能够从文件中选择随机行,则可以使用类似于当前设置的内容,但使用set代替list来快速查找。 通用案例概念验证解决方案可能如下所示:

import random

# Pick 5000 random lines
wanted_lines = set(random.sample(range(200000), 5000)) # Use a set!
for i, line in enumerate(file):
    if i in wanted_lines: # average-case O(1)
        newfile.write(str(line)+'\n')

答案 2 :(得分:1)

我假设您的list是预定义的,并且可以包含任何可能的行索引序列,例如,不一定是每第N行。

第一个可能的瓶颈是您正在进行O(n)列表搜索(i in list)200000次。将列表转换为字典应该有帮助:

listd = dict.fromkeys(list)
.
.
   # this is O(1) instead of O(n)
   if i in listd:

或者,如果您知道list已排序,或者您可以对其进行排序,只需跟踪下一行索引:

list = [0, 2, 4, 6, 8, 10..... 199996, 199998]
nextidx = 0
newfile = open(savefile, "w")
with open("foo.txt", "r") as file:
    for i, line in enumerate(file):
        if i == list[nextidx]:
            newfile.write(line)
            nextidx += 1
newfile.close()

答案 3 :(得分:0)

这样的事情?

flag = False
with open("test_async_db_access.py", "r") as file:
    for line in file:
        if flag:
            print line
        flag = not flag

这避免了必须使用大型列表

编辑:如果它是您想要的任意行列表,那么使用地图{},如DSM的答案,这将在O(1)时间内执行'in'而不是O(n)。