3

問題の解決策が見つからないため、1 つ質問があります。

gen はジェネレーターです (difflib.Differ.compare() の結果):

通常、gen を反復処理することで、各行を読み取ることができます。問題は、反復ごとに現在の行と次の 2 行を読み取る必要があることです。

例 (行ごとに繰り返すことによる通常の出力):

iteration 1:
    line = 'a'
iteration 2:
    line = 'b'
iteration 3:
    line = 'c'
iteration 4:
    line = 'd'
iteration 5:
    line = 'e'
iteration 6:
    line = 'f'
iteration 7: 
    line = 'g'

しかし、私の場合、これを取得する必要があります:

iteration 1:
    line = 'a'
    next1 = 'b'
    next2 = 'c'
iteration 2:
    line = 'b'
    next1 = 'c'
    next2 = 'd'
iteration 3:
    line = 'c'
    next1 = 'd'
    next2 = 'e'
iteration 4:
    line = 'd'
    next1 = 'e'
    next2 = 'f'
iteration 5:
    line = 'e'
    next1 = 'f'
    next2 = 'g'
iteration 6:
    line = 'f'
    next1 = 'g'
    next2 = None
iteration 7: 
    line = 'g'
    next1 = None
    next2 = None

gen.send()、itertools.islice() で遊んでみましたが、適切な解決策が見つかりません。このジェネレーターをリストに変換したくありません (次に、next1 を gen[i + 1] として、next2 を gen[i + 2] として読み取ることができますが、diff 出力が大きい場合、これはまったく非効率的です。

4

5 に答える 5

6

これは、イテレーター/ジェネレーターの一般的な解決策として私が提案するものです。この方法が最も効率的だと思います。

def genby3(gen):
    it = iter(gen) # Make it a separate iterator, to avoid consuming it totally
    L1 = it.next() # Get the first two elements
    L2 = it.next()
    for L3 in it:
        yield [L1, L2, L3] # Get the results grouped in 3
        L1, L2 = L2, L3 # Update the last 2 elements
    yield [L2, L3, None] # And take care of the last 2 cases
    yield [L3, None, None]

print list(genby3(xrange(10)))

読み込んでいたファイルの場合は、seek戻るreadlineことができますが、乱雑になる可能性があるため、他の反復子として扱うことができます。

更新: 反復ごとに 3 つ以上のアイテムでうまく機能するようになりました。他のアイテムと同じように機能します。

def genby(gen, n):
    assert n>=1, 'This does not make sense with less than one element'
    it = iter(gen)
    last = list(it.next() for i in xrange(n-1))

    for nth_item in it:
        last = last+[nth_item]
        yield last
        last.pop(0)

    for i in xrange(n-1):
        last = last+[None]
        yield last
        last.pop(0)

r = xrange(10)
for i, n in enumerate(genby(r, 3)):
    print i, 'iteration'
    print '\t', n

編集 2 : リストの連結を yield ステートメントの前に移動しました。これは、2 回行う必要がないようにするためです。パフォーマンスがわずかに向上します。

于 2012-12-05T21:03:48.290 に答える
3

一時変数を保持してみてください。

line = iterator.next()
next1 = iterator.next()

for next2 in iterator:
    #do stuff
    line = next1
    next1 = next2
于 2012-12-05T20:55:40.920 に答える
2

ドキュメントにレシピitertoolsがあります、pairwise()。それは適応することができます:

from itertools import tee, izip_longest

def triplewise(iterable):
    xs, ys, zs = tee(iterable, 3)
    next(ys, None)
    next(zs, None)
    next(zs, None)
    return izip_longest(xs, ys, zs)

for line, next1, next2 in triplewise(gen):
    ...

一般化することもできます。

from itertools import tee, izip, izip_longest, islice

no_fillvalue = object()

def nwise(iterable, n=2, fillvalue=no_fillvalue):
    iters = (islice(each, i, None) for i, each in enumerate(tee(iterable, n)))
    if fillvalue is no_fillvalue:
        return izip(*iters)
    return izip_longest(*iters, fillvalue=fillvalue)

for line, next1, next2 in nwise(gen, 3, None):
    ...
于 2012-12-05T21:09:44.307 に答える
1

3 つのシーケンスを一緒に圧縮するのはどうですか?

izip_longest(gen, islice(gen,1,None), islice(gen,2,None), fillvalue=None)
于 2012-12-05T20:55:52.047 に答える
1

次のようなものを使用できます。

def genTriplets(a):
    first = a.next()
    second = a.next()
    third = a.next()
    while True:
        yield (first, second, third)
        first = second
        second = third
        try:
            third = a.next()
        except StopIteration:
            third = None
            if (first is None and second is None and third is None):
                break
于 2012-12-05T21:12:24.653 に答える