Python嵌套循环 - 接下来的N行

时间:2013-12-10 00:05:57

标签: python loops nested

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

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

现在我只是试图让循环使用rownumbers而不是字符串,因为它更容易可视化。我提出了这个代码,但它的表现并不像我想要的那样:

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)

5 个答案:

答案 0 :(得分:5)

根据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 :(得分:1)

您可以使用切片执行此操作。如果您首先将整个文件读入列表,这是最简单的:

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]。请注意,切片包含起始索引处的项目,但结束索引处的项目,因此需要高于当前上限的项目。

答案 2 :(得分:0)

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

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]

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

答案 3 :(得分:0)

由于这是一个非常大的文件,您可能不希望一次将其全部加载到内存中。因此,为了避免多次读取一行,这就是你所做的。

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

    • 当您阅读第一行时,请将其添加到列表中的第一项。
    • 将巢线添加到第一个和第二个项目。
    • 每行
    • 等等
  • 当该列表中的项目达到长度N时,将其取出并将其附加到输出文件中。并在末尾添加一个空项目,这样您仍然可以列出N个项目。

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

答案 4 :(得分:0)

根据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
相关问题