【问题标题】:Python nested loop - get next N linesPython嵌套循环 - 获取下N行
【发布时间】:2013-12-27 07:40:18
【问题描述】:

我是 Python 新手,正在尝试做一个嵌套循环。我有一个非常大的文件(110 万行),我想用它来创建一个文件,其中包含每一行以及接下来的 N 行,例如接下来的 3 行:

1    2
1    3
1    4
2    3
2    4
2    5

现在我只是想让循环使用行号而不是字符串,因为它更容易可视化。我想出了这段代码,但它的行为不像我想要的那样:

with open('C:/working_file.txt', mode='r', encoding = 'utf8') as f: 
for i, line in enumerate(f):
     line_a = i
     lower_bound = i + 1
     upper_bound = i + 4
     with open('C:/working_file.txt', mode='r', encoding = 'utf8') as g:
        for j, line in enumerate(g):
            while j >= lower_bound and j <= upper_bound:
                line_b = j
                j = j+1
                print(line_a, line_b)

而不是像上面我想要的输出,它给了我这个:

990     991
990     992
990     993
990     994
990     992
990     993
990     994
990     993
990     994
990     994

正如您所见,内循环对外循环中的每一行都进行了多次迭代。似乎外循环中的每行应该只有一次迭代。我错过了什么?

编辑:我的问题在下面得到了回答,这是我最终使用的确切代码:

from collections import deque
from itertools import cycle
log = open('C:/example.txt', mode='w', encoding = 'utf8') 
try:
    xrange 
except NameError: # python3
    xrange = range

def pack(d):
    tup = tuple(d)
    return zip(cycle(tup[0:1]), tup[1:])

def window(seq, n=2):
    it = iter(seq)
    d = deque((next(it, None) for _ in range(n)), maxlen=n)
    yield pack(d)
    for e in it:
        d.append(e)
        yield pack(d)

for l in window(open('c:/working_file.txt', mode='r', encoding='utf8'),100):
    for a, b in l:
        print(a.strip() + '\t' + b.strip(), file=log)

【问题讨论】:

  • for j, line in enumerate(g)j = j+1 永远不应该在一起......
  • 我看不出它还能如何工作 - 你在一个循环中有一个循环。当然,line_a 通过文件 g 进行的所有迭代都保持不变。
  • @sashkello 为什么不应该这样做?什么是替代方案?我刚开始学习python。
  • for i in mylist 遍历mylist 中的所有对象。同时修改i 会使程序混乱,因为i 不一定在列表中。在你的情况下,你可以做for n in range(lower_bound, upper_bound+1)

标签: python loops nested


【解决方案1】:

我认为解决此问题的最简单方法是将文件读入字典...

my_data = {}
for i, line in enumerate(f):
    my_data[i] = line

完成后就可以了

for x in my_data:
    for y in range(1, 4):
        print my_data[x], my_data[x + y]

正如所写,您正在为每一行读取百万行文件一百万次......

【讨论】:

  • 谢谢 Paul - 我对你的建议是否正确?我收到一个错误: f = open('C:/working_file.txt', mode='r', encoding = 'utf8') my_data = {} for i, line in f: my_data[i] = line for x in my_data: for y in range(1, 4): out.write(my_data[x] + " " + my_data[x + y]
  • 你遇到了什么错误?我刚刚重新阅读了您的代码,并意识到您正在使用 print 语句进行输出-我将 out.write 更改为 print
  • 这里是错误:回溯(最近一次调用最后):文件“loop_test.py”,第 20 行,在 for i,f 中的行:ValueError:要解压的值太多(预期2)
  • 我忘记了第一个循环中的枚举。我很抱歉。
  • 转换为 dict 是不必要的开销,因为您必须构建它,至少评估所有键(即文件中的所有行)的哈希值,而您可以改为对列表进行操作;此外,加载所有文件也是不必要的开销,这种方法结合了这两者。
【解决方案2】:

你可以用切片来做到这一点。如果您先将整个文件读入列表,这是最简单的:

with open('C:/working_file.txt', mode='r', encoding = 'utf8') as f: 
    data = f.readlines()

for i, line_a in enumerate(data):
    for j, line_b in enumerate(data[i+1:i+5], start=i+1):
        print(i, j)

当您将其更改为打印行而不是行号时,您可以删除第二个enumerate 并执行for line_b in data[i+1:i+5]。请注意,切片包含起始索引处的项目,但不包含结束索引处的项目,因此它需要比当前上限高一。

【讨论】:

    【解决方案3】:

    基于old docs 的窗口示例,您可以使用以下内容:

    from collections import deque
    from itertools import cycle
    
    try:
        xrange 
    except NameError: # python3
        xrange = range
    
    def pack(d):
        tup = tuple(d)
        return zip(cycle(tup[0:1]), tup[1:])
    
    def window(seq, n=2):
        it = iter(seq)
        d = deque((next(it, None) for _ in xrange(n)), maxlen=n)
        yield pack(d)
        for e in it:
            d.append(e)
            yield pack(d)
    

    演示:

    >>> for l in window([1,2,3,4,5], 4):
    ...     for l1, l2 in l:
    ...         print l1, l2
    ...
    1 2
    1 3
    1 4
    2 3
    2 4
    2 5
    

    所以,基本上你可以将文件传递到窗口以获得所需的结果:

    window(open('C:/working_file.txt', mode='r', encoding='utf8'), 4)
    

    【讨论】:

    • +1 用于迭代工具。这比我使用readlines 的解决方案要好得多,因为它不会将整个文件读入内存。但请注意,OP 似乎使用的是 Python 3,因此某些代码需要调整 - 例如,xrange -> range 会跳出。
    • +1 用于使用我以前见过的食谱,而不是重新发明轮子。
    • 这对我来说非常适合,只需稍作调整 - 谢谢!我用我使用的确切代码更新了我的问题。
    【解决方案4】:

    由于这是一个相当大的文件,您可能不想一次将其全部加载到内存中。因此,为了避免多次阅读一行,这就是你要做的。

    • 创建一个包含 N 个元素的列表,其中 N 是要读取的下一行的数量。

      • 当您阅读第一行时,将其添加到列表中的第一项。
      • 将嵌套线添加到第一项和第二项。
      • 每行以此类推
    • 当该列表中的项目达到长度 N 时,将其取出并将其附加到输出文件中。并在最后添加一个空项目,这样你仍然有一个包含 N 个项目的列表。

    这样您只需要读取每一行一次,而不必将整个文件加载到内存中。你只需要保持,最大,N!内存中的行。

    【讨论】:

    • 这大致是 alko 的 itertools solution 所做的,除了它使用 O(N) 内存而不是 O(N!)。
    【解决方案5】:

    根据 alko 的回答,我建议使用未经修改的 window 配方

    from itertools import islice
    
    def window(seq, n=2):
        "Returns a sliding window (of width n) over data from the iterable"
        "   s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ...                   "
        it = iter(seq)
        result = tuple(islice(it, n))
        if len(result) == n:
            yield result    
        for elem in it:
            result = result[1:] + (elem,)
            yield result
    
    for l in window([1,2,3,4,5], 4):
        for item in l[1:]:
            print l[0], item
    

    【讨论】:

      猜你喜欢
      • 2020-05-25
      • 2016-10-18
      • 1970-01-01
      • 2020-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-04
      相关资源
      最近更新 更多