6

now, next ペアを返す iterable を反復処理できる一般的な関数を作成します。

def now_nxt(iterable):
    iterator = iter(iterable)
    nxt = iterator.__next__()
    for x in iterator:
        now = nxt
        nxt = x
        yield (now,nxt) 

for i in now_nxt("hello world"):
    print(i)

('h', 'e')
('e', 'l')
('l', 'l')
('l', 'o')
('o', ' ')
(' ', 'w')
('w', 'o')
('o', 'r')
('r', 'l')
('l', 'd')

各タプルの項目数を設定できる関数を書く最善の方法を考えていました。

たとえば、

func("hello",n=3)

結果は次のようになります。

('h','e','l')
('e','l','l')
('l','l','o')

私はtimeitを初めて使用するので、ここで何か間違ったことをしている場合は指摘してください:

import timeit

def n1(iterable, n=1):
    #now_nxt_deque
    from collections import deque
    deq = deque(maxlen=n)
    for i in iterable:
        deq.append(i)
        if len(deq) == n:
            yield tuple(deq)

def n2(sequence, n=2):
    # now_next
    from itertools import tee
    iterators = tee(iter(sequence), n)
    for i, iterator in enumerate(iterators):
        for j in range(i):
            iterator.__next__()
    return zip(*iterators)

def n3(gen, n=2):
    from itertools import tee, islice
    gens = tee(gen, n)
    gens = list(gens)
    for i, gen in enumerate(gens):
        gens[i] = islice(gens[i], i, None) 
    return zip(*gens)


def prin(func):
    for x in func:
        yield x

string = "Lorem ipsum tellivizzle for sure ghetto, consectetuer adipiscing elit."

print("func 1: %f" %timeit.Timer("prin(n1(string, 5))", "from __main__ import n1, string, prin").timeit(100000))
print("func 2: %f" %timeit.Timer("prin(n2(string, 5))", "from __main__ import n2, string, prin").timeit(100000))
print("func 3: %f" %timeit.Timer("prin(n3(string, 5))", "from __main__ import n3, string, prin").timeit(100000))

結果:

$  py time_this_function.py 
func 1: 0.163129
func 2: 2.383288
func 3: 1.908363
4

5 に答える 5

5

私の提案は、

from collections import deque

def now_nxt_deque(iterable, n=1):
    deq = deque(maxlen=n)
    for i in iterable:
        deq.append(i)
        if len(deq) == n:
            yield tuple(deq)

for i in now_nxt_deque("hello world", 3):
    print(i)

('h', 'e', 'l')
('e', 'l', 'l')
('l', 'l', 'o')
('l', 'o', ' ')
('o', ' ', 'w')
(' ', 'w', 'o')
('w', 'o', 'r')
('o', 'r', 'l')
('r', 'l', 'd')
于 2012-06-22T21:24:10.843 に答える
5

これを行うための本当に簡単な方法は次のとおりです。

  • nを使用してイテレータ時間を複製しますitertools.tee
  • i番目の反復子iを進める
  • izipそれらをすべて一緒に
import itertools

def now_next(sequence, n=2):
    iterators = itertools.tee(iter(sequence), n)
    for i, iterator in enumerate(iterators):
        for j in range(i):
            iterator.next()
    return itertools.izip(*iterators)
于 2012-06-22T21:30:29.053 に答える
2

私の解決策:

def nn(itr, n):
    iterable = iter(itr)

    last = tuple(next(iterable, None) for _ in xrange(n))
    yield last
    for _ in xrange(len(itr)):
        last = tuple(chain(last[1:], [next(iterable)]))
        yield last

これは Python 2 用に作成されたものです。Python 3 で使用する場合はxrangerange.

nextdefaultには、 を発生させる代わりに返される優れたパラメータがありStopIterationます。次のように、このデフォルト パラメータを関数に追加することもできます。

def nn(itr, n, default=None):
    iterable = iter(itr)

    last = tuple(next(iterable, default) for _ in xrange(n))
    yield last
    for _ in xrange(len(itr)):
        last = tuple(chain(last[1:], [next(iterable, default)]))
        yield last

デフォルトとして使用するなど、もう少し遊んでみましitr.__class__()たが、リストとタプルには間違っているようです。文字列には意味があります。

于 2012-06-22T21:24:59.633 に答える
1

スライスを使用するエリックのテクニックのバリエーション

from itertools import tee, islice, izip

def now_next(gen, n=2):
  gens = tee(gen, n)
  gens = list(gens)
  for i, gen in enumerate(gens):
    gens[i] = islice(gens[i], i, None) 
  return izip(*gens)

for x in now_next((1,2,3,4,5,6,7)):
  print x
于 2012-06-22T23:39:37.843 に答える
0

cravooriの答えに基づくワンライナー:

from itertools import tee, islice, izip

def now_next(gen, n=2):
    return izip(*(islice(g, i, None) for i, g in enumerate(tee(gen, n))))
于 2012-06-23T07:49:29.243 に答える