2017-04-19 14 views
0

私は、1つのインデックスだけが "移動する"リスト内の連続したアイテムの数を返すジェネレータを作ろうとしています。 DSPの移動平均フィルタに似たもの。私はリストがある場合たとえば:アイテムのグループを返すPythonジェネレータ

l = [1,2,3,4,5,6,7,8,9] 

を、私はこの出力を期待する:

[(1,2,3),(2,3,4),(3,4,5),(4,5,6),(5,6,7),(6,7,8),(7,8,9)] 

私はそれも原因壊れる怖い私は、コードを作ったが、それは、フィルタや発電機などでは動作しません。私は大きな単語のリストを提供する必要がある場合、メモリに。

機能gen

def gen(enumobj, n): 
    for idx,val in enumerate(enumobj): 
     try: 
      yield tuple(enumobj[i] for i in range(idx, idx + n)) 
     except: 
      break 

とサンプルコード:

words = ['aaa','bb','c','dddddd','eeee','ff','g','h','iiiii','jjj','kk','lll','m','m','ooo'] 
w = filter(lambda x: len(x) > 1, words) 

# It's working with list 
print('\nList:') 
g = gen(words, 4) 
for i in g: print(i) 

# It's not working with filetrs/generators etc. 
print('\nFilter:') 
g = gen(w, 4) 
for i in g: print(i) 

何も発生しないためのリスト。コードは、フィルターオブジェクトを索引付けすることができないため、中断されるはずです。もちろん答えの1つはリストを強制的に入力することです:list(w)。しかし、私は関数のより良いコードを探しています。どのように機能をフィルタなどを受け入れることができるように私はそれを変更することができます。私はリストの膨大な数のデータにメモリが心配です。

おかげで既に読み込まれた値を追跡する必要がイテレータで

答えて

1

nのサイズのリストはトリックを行います。リストに次の値を追加し、各利回りの後に最上位の項目を破棄します。

import itertools 

def gen(enumobj, n): 
    # we need an iterator for the `next` call below. this creates 
    # an iterator from an iterable such as a list, but leaves 
    # iterators alone. 
    enumobj = iter(enumobj) 
    # cache the first n objects (fewer if iterator is exhausted) 
    cache = list(itertools.islice(enumobj, n)) 
    # while we still have something in the cache... 
    while cache: 
     yield cache 
     # drop stale item 
     cache.pop(0) 
     # try to get one new item, stopping when iterator is done 
     try: 
      cache.append(next(enumobj)) 
     except StopIteration: 
      # pass to emit progressively smaller units 
      #pass 
      # break to stop when fewer than `n` items remain 
      break 

words = ['aaa','bb','c','dddddd','eeee','ff','g','h','iiiii','jjj','kk','lll','m','m','ooo'] 
w = filter(lambda x: len(x) > 1, words) 

# It's working with list 
print('\nList:') 
g = gen(words, 4) 
for i in g: print(i) 

# now it works with iterators 
print('\nFilter:') 
g = gen(w, 4) 
for i in g: print(i) 
+0

こんにちは。私はいくつかのことについて尋ねる必要があります。最初の2行はジェネレータを初期化し、ジェネレータが動作を開始したときにのみ実行されると言っていますか? iterableはオブジェクトを最初にスライスする必要があるようです。どのような種類の条件が 'while data:'行でチェックされ、なぜ 'data'ですか?私にとって、この関数は 'yield data'を介して値を返し、それが一時停止するとコードは次の行に戻ります。あれは正しいですか?すみません、私は発電機を作るのが初めてです。ありがとう – Celdor

+0

私は 'pass'を' break'に変更しました。それ以外の場合、関数は長さn-1、n-2、..、1の余分な項目を返します。 – Celdor

+0

これは、イテレータの開始項目がn個未満の場合にも問題になります。 'islice'の直後にチェックを追加してすぐに戻ることができます。 – tdelaney

関連する問題