2011-08-08 37 views
2

我有一個名爲元組(假設每個元組有N個值)的2維列表,我想他們解壓到N個不同的2維列出每個解壓2 -D列表完全由原始列表中的單個屬性組成。例如,如果我有這樣的2-d列表:Python的解壓命名元組的2維列表

>>> 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個結果是:

[[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']] 

如果我只是有一個元組的1維列表我會使用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

非常好,我喜歡使用'getattr()'而不是枚舉私有變量'_fields'。它看起來更清潔。 –

+0

我原本在我的'getattr'中使用過,但覺得'getattr'不夠乾淨。:-) – kindall

+0

我仍然使用'_fields'。不知道是否有辦法得到沒有它的命名元組字段名稱的列表 – Claudiu

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

啊哈好,我不知道名字有個'_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。 –