1

如何将所有偶数行从一个文件复制到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

4 回答 4

2

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

keep = {1, 5, 888, 20203} 

接着

if i in keep:
于 2013-06-05T14:58:45.550 回答
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()
于 2013-06-05T15:03:18.737 回答
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')
于 2013-06-05T14:56:49.243 回答
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 的答案这样的 map {},这将在 O(1) 时间而不是 O(n) 中执行“in”。

于 2013-06-05T14:57:04.520 回答