2011-08-08 9 views
2

名前付きタプルの2次元リストを持っています(それぞれのタプルにN値があるとします)、それらをN個の異なる2次元リストに展開したい-Dリストは、元のリストの単一の属性から完全に構成されています。私はこの2-Dのリストを持っている場合たとえば:私はちょうど私が使用したいタプルの1次元のリストを持っていた場合Pythonは名前付きタプルの2次元リストを展開します

[[0, 1, 2], 
[3, 4, 5], 
[6, 7, 8]] 

[[0.0, 1.0, 2.0], 
[3.0, 4.0, 5.0], 
[6.0, 7.0, 8.0]] 

[['0', '1', '2'], 
['3', '4', '5'], 
['6', '7', '8']] 

>>> combo = namedtuple('combo', 'i, f, s') 
>>> combo_mat = [[combo(i + 3*j, float(i + 3*j), str(i + 3*j)) for i in range(3)] 
       for j in range(3)] 
>>> combo_mat 
[[combo(i=0, f=0.0, s='0'), combo(i=1, f=1.0, s='1'), combo(i=2, f=2.0, s='2')], 
[combo(i=3, f=3.0, s='3'), combo(i=4, f=4.0, s='4'), combo(i=5, f=5.0, s='5')], 
[combo(i=6, f=6.0, s='6'), combo(i=7, f=7.0, s='7'), combo(i=8, f=8.0, s='8')]] 

私がする3件の結果をみたいです以下のようなzip(*mylist)、:

>>> zip(*[combo(i=0, f=0.0, s='0'), combo(i=1, f=1.0, s='1'), combo(i=2, f=2.0, s='2')]) 
[(0, 1, 2), (0.0, 1.0, 2.0), ('0', '1', '2')] 

そして私はちょうどネスティングによって私の状況にこれを拡張することができます。

>>> zip(*[zip(*combs) for combs in combo_mat]) 
[((0, 1, 2), 
    (3, 4, 5), 
    (6, 7, 8)), 
((0.0, 1.0, 2.0), 
    (3.0, 4.0, 5.0), 
    (6.0, 7.0, 8.0)), 
(('0', '1', '2'), 
    ('3', '4', '5'), 
    ('6', '7', '8'))] 

しかし、これは私が望むリストを私に与えてくれないし、ネストされたアンパックzip(*)関数はそれを読むことができません。誰かがもっとpythonicソリューションのためのアイデアを持っていますか?ボーナスは、最終結果のどこかでタプルの属性の名前を処理できる場合に発生します。これは、することができ

{'i': [[0, 1, 2], 
     [3, 4, 5], 
     [6, 7, 8]], 
'f': [[0.0, 1.0, 2.0], 
     [3.0, 4.0, 5.0], 
     [6.0, 7.0, 8.0]] 
's': [['0', '1', '2'], 
     ['3', '4', '5'], 
     ['6', '7', '8']]} 

答えて

3

関数型プログラミングの救助に?それは本質的にジッパーをネストのクリーンバージョンです:

def fmap_element(f, el): 
    return f(el) 

def fmap_list(f, l): 
    return [fmap_element(f, el) for el in l)] 

def fmap_lol(f, lol): 
    return [fmap_list(f,l) for l in lol] 

def split_nt_lol(nt_lol): 
    return dict((name, fmap_lol(lambda nt: getattr(nt, name), nt_lol)) 
       for name in nt_lol[0][0]._fields) 

使用法:

>>> split_nt_lol(combo_mat) 
{'i': [[0, 1, 2], [3, 4, 5], [6, 7, 8]], 
's': [['0', '1', '2'], ['3', '4', '5'], ['6', '7', '8']], 
'f': [[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]]} 
+0

優れています。プライベート変数 '_fields'を列挙するのではなく、' getattr() 'を使うのが好きです。それはより清潔に見える。 –

+0

私はもともと 'getattr'を鉱山で使っていましたが、' getattr'はきれいではないと感じました。:-) – kindall

+0

私はまだ '_fields'を使います。それがなければ名前付きタプルのフィールド名のリストを取得する方法があるかどうかは分かりません。 – Claudiu

0

:私はのように、そのそれぞれのマトリックスにタプル属性の名前をマッピングされた辞書を持っていることができれば

実は、今、私はそれを考えること、それは、理想的だろうtranspose()を使用して配列をトランスポーズするだけで簡単に実現できます。

参考: http://www.astro.ufl.edu/~warner/prog/python.html(ワード "転置" で検索)

+0

うん、私はまったくそれを得ていない。あなたは何を意味するのか説明できますか? –

2
matrices = {} 

for num, name in enumerate(combo._fields): 
    matrix = [] 
    for i in combo_mat: 
     row = [] 
     for j in i: 
      row.append(j[num]) 
     matrix.append(row) 
    matrices[name] = matrix 
+0

Aha良いこと、名前付きタプルに '_fields'属性があることはわかりませんでした。 –

+0

しかし、属性名、値のペアにアクセスするより直接的な方法はありますか?たぶん私は辞書に格納する必要があります。 –

+0

ああ、私よりもpythonic .. – Claudiu

1

これは、任意のより読みやすく、ネストされたzip(*)機能以外ではありませんが、それは仕事をしていません:

>>> dict((key, [[c._asdict()[key] for c in combos] for combos in combo_mat]) 
     for key in ['i', 'f', 's']) 
{'i': [[0, 1, 2], [3, 4, 5], [6, 7, 8]], 
's': [['0', '1', '2'], ['3', '4', '5'], ['6', '7', '8']], 
'f': [[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]]} 

私はそれを少し読みやすくすることができると思います:

def get_mat(combo_mat, key): 
    return [[c._asdict()[key] for c in combos] for combos in combo_mat] 

def get_mat_dict(combo_mat, keys): 
    return dict((key, get_mat(combo_mat, key)) for key in keys) 
+0

うーん、私はそれが好きだけど、特に読めるわけではないという点であなたは正しい。 –

+0

優れたリビジョン、可能ならば+1します。 –

関連する問題