4

次の形式でデータベースから戻ってくる一連のレコードがあります。

data = [
    ["date", "value1a", "value2a", "value3a", ...],
    ["date", "value1b", "value2b", "value3b", ...]
]

その行のセットを次のようなリストに変換したい

[
    [("date", "value1a"), ("date", "value1b"), ... ],
    [("date", "value2a"), ("date", "value2b"), ... ]
]

zip()はこの種のことを行うことを知っていますが、各レコードに日付を取得する方法(およびそれらをタプルにする方法)が明確ではありません。データベースから返される行の長さは常に同じであるとは限りませんが、各呼び出しで予想される長さはわかります。

4

4 に答える 4

4
data = [["date_a", "1a", "2a", "3a"], 
        ["date_b", "1b", "2b", "3b"]]

print zip(*(zip(itertools.repeat(ls[0]), ls[1:]) for ls in data))

与える

[(('date_a', '1a'), ('date_b', '1b')),
 (('date_a', '2a'), ('date_b', '2b')),
 (('date_a', '3a'), ('date_b', '3b'))]

いくつかの便利なバリエーションについては、コメントを参照してください。

于 2012-05-21T19:18:49.220 に答える
2

最初の要素にitertoolsrepeatを使用します。

zip(itertools.repeat(ls[0]), ls[1:])
于 2012-05-21T15:31:34.503 に答える
2

編集:これは、データが複数の入力リストではなく、単一のリストにあるという仮定の下での元の質問に基づいていました。質問を編集したことで、これが当てはまらないことが明らかになったので、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)))

はるかに読みやすいです。

于 2012-05-21T16:15:19.313 に答える
0

これは、単純なリスト内包法でも実現できます。

data = [    ["date1", "value1a1", "value2a1", "value3a1"],
            ["date2", "value1b2", "value2b2", "value3b2"]
       ]
result = map(list, zip(*[[(x[0], x[i]) for x in data] for i in range(1,len(x))]))

[
  [('date1', 'value1a1'), ('date1', 'value2a1'), ('date1', 'value3a1')],
  [('date2', 'value1b2'), ('date2', 'value2b2'), ('date2', 'value3b2')]
]
于 2013-02-25T07:32:06.227 に答える