編集:これは、データが複数の入力リストではなく、単一のリストにあるという仮定の下での元の質問に基づいていました。質問を編集したことで、これが当てはまらないことが明らかになったので、JanneKarilaの解決策に従うことをお勧めします。
異なる値がいくつあるかを知っていると仮定すると、これはitertools
'grouper()
レシピを使用した良い解決策です:
import itertools
def grouper(n, iterable, fillvalue=None):
args = [iter(iterable)] * n
return itertools.zip_longest(fillvalue=fillvalue, *args)
data = ["date", "1a", "2a", "3a", "1b", "2b", "3b", "1c", "2c", "3c"]
first = data.pop(0)
print([list(zip(itertools.repeat(first), items)) for items in zip(*grouper(3, data))])
私たちに与える:
[
[('date', '1a'), ('date', '1b'), ('date', '1c')],
[('date', '2a'), ('date', '2b'), ('date', '2c')],
[('date', '3a'), ('date', '3b'), ('date', '3c')]
]
None
十分な値がない場合、これによりリストにsが埋め込まれることに注意してください。
当然、リスト内包表記の代わりにジェネレーター内包表記を使用することもできます。たとえば、リスト内包表記を表示せずにループしたい場合です。例えば:
(zip(itertools.repeat(first), items) for items in zip(*grouper(3, data)))
私はPython3.xを使用していることに注意してください。したがって、2.xでは、どこで使用しzip()
ても、おそらく必要になりitertools.izip()
、にitertools.zip_longest()
なりitertools.izip_longest()
ます。
これを行うためのより良い方法に注意してください-最初のリストにあるべき値を定義するもの、2番目のリストにあるべきものなどを知っていると仮定します...
import itertools
import operator
data = ["date", "1a", "2a", "3a", "1b", "2b", "3b", "1c", "2c", "3c"]
first = data.pop(0)
print([list(zip(itertools.repeat(first), items)) for _, items in itertools.groupby(sorted(data), operator.itemgetter(0))])
生成するもの:
[
[('date', '1a'), ('date', '1b'), ('date', '1c')],
[('date', '2a'), ('date', '2b'), ('date', '2c')],
[('date', '3a'), ('date', '3b'), ('date', '3c')]
]
当然、これは特定の例でのみ機能します。実際のデータが異なると仮定するとoperator.itemgetter(0)
、アイテムをグループ化するリストを定義する関数に変更する必要があります。
プレフィックス作業をカプセル化する価値があるかもしれないことに注意してください。
def prefix(iterable, prefix):
"""Returns every element of an iterable prefixed with a given value."""
#prefix("ABCDEFG", "x") --> ("x", "A"), ("x", "B"), ("x", "C"), ("x", "D"), ...
return zip(itertools.repeat(prefix), iterable)
そして、次のようになります。
(prefix(items, first) for items in zip(*grouper(3, data)))
と
(prefix(items, first) for _, items in itertools.groupby(sorted(data), operator.itemgetter(0)))
はるかに読みやすいです。