Pythonでは、nがkの倍数である場合(IOW、 )、 n個の長いリストをkサイズのチャンクに分割するのは簡単です。これが私のお気に入りのアプローチです(ドキュメントから直接):n % k == 0
>>> k = 3
>>> n = 5 * k
>>> x = range(k * 5)
>>> zip(*[iter(x)] * k)
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 14)]
(トリックは、によって返される、同じイテレータへのk個の参照[iter(x)] * k
のリストを生成することです。次に、イテレータのk個のコピーのそれぞれを1回だけ呼び出すことによって、各チャンクを生成します。「イテレータのリストではなく、イテレータ。)iter(x)
zip
*
[iter(x)] * k
zip
このイディオムで私が目にする主な欠点は、nがkの倍数(IOW、n % k > 0
)でない場合、残りのエントリが省略されることです。例えば:
>>> zip(*[iter(x)] * (k + 1))
[(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)]
入力するのが少し長く、上記の場合と同じ結果を生成し、次の場合n % k == 0
により許容可能な動作をする代替イディオムがありn % k > 0
ます。
>>> map(None, *[iter(x)] * k)
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 14)]
>>> map(None, *[iter(x)] * (k + 1))
[(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11), (12, 13, 14, None)]
少なくとも、ここでは残りのエントリは保持されますが、最後のチャンクには。が埋め込まれNone
ます。パディングに別の値が必要な場合はitertools.izip_longest
、問題を解決します。
ただし、目的のソリューションが、最後のチャンクがパディングされないままになっているソリューションであるとします。
[(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11), (12, 13, 14)]
この結果を生成するためにイディオムを変更する簡単な方法はありますか?map(None, *[iter(x)]*k)
(確かに、関数を記述してこの問題を解決することは難しくありません(たとえば、リストを均等なサイズのチャンクに分割するにはどうすればよいですか?またはしたがって、この質問のより正確なタイトルは「イディオムをどのように救うか」ですmap(None, *[iter(x)]*k)
が、多くの読者を困惑させると思います。)
私は、リストを均等なサイズのチャンクに分割するのがいかに簡単であるか、そして2つの問題が同等の複雑さのように見えても、不要なパディングを取り除くのがいかに難しいか(比較して! )に感銘を受けました。