他の回答が指摘したように、oil_changes
リストが非常に長くない限り、実際に心配する必要はありません。しかし、「ストリームベース」コンピューティングのファンとして、 O(1) 空間 (そしてもちろん O(N) 時間!-) で値itertools
を計算するために必要なすべてのツールを提供することを指摘するのは興味深いと思います。 next_oil
N、つまり がどれだけ大きくなってもlen(next_oil)
。
izip
乗法定数を少し減らすだけで、スペースの需要をO(N)のままにするため、それ自体では不十分です。これらの要求を O(1) に下げるための重要なアイデアはizip
、tee
-- と組み合わせることであり、リスト内包表記を回避することです。これはとにかく空間では O(N) であり、シンプルで昔ながらのループを優先します!-)。の登場:
it = iter(oil_changes)
a, b = itertools.tee(it)
b.next()
thesum = 0
for thelen, (i, j) in enumerate(itertools.izip(a, b)):
thesum += j - i
last_one = j
next_oil = last_one + thesum / (thelen + 1)
リストからスライスを取得する代わりに、イテレータを取得し、それをティー (独立して進めることができるその 2 つのクローンを作成) し、クローンの 1 つを 1 回進めb
ます。tee
スペース O(x) を取ります。x は、さまざまなクローンの前進の最大絶対差です。ここでは、2 つのクローンの進行状況の違いは最大でも 1 だけであるため、必要なスペースは明らかに O(1) です。
izip
わずかに斜めになった 2 つのクローン イテレータを 1 つずつ「圧縮」し、それをドレスアップしenumerate
て、ループを何回通過したか、つまり、反復している iterable の長さを追跡できるようにします。オン ( enumerate
0 から始まるため、最後の式に +1 が必要です!-)。単純な で合計を計算し+=
ます。これは数値には問題ありません (sum
さらに優れていますが、長さを追跡しません!-)。
ループの後で を使用するのは魅力的ですが、それは実際には使い果たさlast_one = a.next()
れているため機能しません--は引数 iterables を左から右に進めます。つまり、終わったことに気付く前に最後にもう 1 回進めてしまいます!-)。Python ループ変数のスコープはループ自体に限定されていないため、問題ありません。ループの後、あきらめる前に前進することによって最後に抽出された値がまだ残っています(によって返された最後のカウント値がまだ残っているのと同じように)。最終的な式で直接使用するのではなく、値に名前を付けています。これは、より明確で読みやすいと思うためです。a
izip
a
b
j
b
izip
thelen
enumerate
last_one
j
というわけで -- 参考になれば幸いです!-) -- ただし、今回あなたが提起した特定の問題の解決策については、やり過ぎであることはほぼ確実です。私たちイタリア人には、古代からのことわざがあります。非常に難しい問題に遭遇した場合に備えて、非常に難しい問題を解決するための高度で洗練された方法。必要ありません!-)