2012-07-23 244 views
4

的字典假設以下toyset(從CSV文件,其中列名是「鑰匙」,我只在某些行,我把在「數據」有興趣):將項目添加到列表

keys = ['k1', 'k2', 'k3', 'k4'] 
data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]] 

我希望得到一個字典,爲每一列一個清單,這樣的:

{'k1': [1, 5, 9, 13], 'k2': [2, 6, 10, 14], 'k3': [3, 7, 11, 15], 'k4': [4, 8, 
12, 16]} 

在我的代碼我第一次初始化以空列表的字典,然後遍歷(中鍵的順序),追加每項目在他們的列表中。

my_dict = dict.fromkeys(keys, []) 
for row in data: 
    for i, k in zip(row, keys): 
     my_dict[k].append(i) 

但它不起作用。它建立本字典:

{'k3': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], 'k2': [1, 2, 3, 
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], 'k1': [1, 2, 3, 4, 5, 6, 7, 8, 
9, 10, 11, 12, 13, 14, 15, 16], 'k4': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 
13, 14, 15, 16]} 

你可以看到,所有的元素都在所有列表,而不是在每個名單只是四個元素。如果我在循環中打印i,k,它會執行正確的項目和鍵對。所以我想問題是當我在關鍵字k的列表中添加項目i時。

有誰知道爲什麼所有元素都添加到所有列表中,並且什麼是構建我的字典的正確方法?

在此先感謝

回答

6

壓縮,但第一調換它:

>>> keys = ['k1', 'k2', 'k3', 'k4'] 
>>> data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]] 
>>> print dict(zip(keys, zip(*data))) 
{'k3': (3, 7, 11, 15), 'k2': (2, 6, 10, 14), 'k1': (1, 5, 9, 13), 'k4': (4, 8, 12, 16)} 

如果你想名單不是數組中的元組:

>>> print dict(zip(keys, [list(i) for i in zip(*data)])) 

如果你想用你的版本,只要字典理解,不fromkeys

my_dict = { k : [] for k in keys } 

在你的情況下,你初始化的問題my_dict具有相同值:

>>> my_dict = dict.fromkeys(keys, []) 
>>> my_dict 
{'k3': [], 'k2': [], 'k1': [], 'k4': []} 
>>> my_dict['k3'].append(1) 
>>> my_dict 
{'k3': [1], 'k2': [1], 'k1': [1], 'k4': [1]} 

當你這樣做的權利(與詞典/列表理解):

>>> my_dict = dict((k, []) for k in keys) 
>>> my_dict 
{'k3': [], 'k2': [], 'k1': [], 'k4': []} 
>>> my_dict['k3'].append(1) 
>>> my_dict 
{'k3': [1], 'k2': [], 'k1': [], 'k4': []} 
+0

感謝您使用「相同值」的解釋,這非常有幫助 – julia 2012-07-23 13:32:51

4

我認爲dict(zip(keys, map(list,zip(*data))))應該做的伎倆。

首先,我轉置您的數據(zip(*data)),但它會返回元組...因爲您想要列表,所以我使用map來構造元組中的列表。然後我們再次使用zip來匹配鍵和列表中的項目。例如(key1,list1), (key2,list2),...。這正是字典構造器所期望的,所以你是金。

另一種解決辦法是使用一個collections.defaultdict

d=collections.defaultdict(list) 
tdata=zip(*data) #transpose your data 
for k,v in zip(keys,tdata): 
    d[k].extend(v) 

當然,這給你留下一個defaultdict,而不是常規的一個,雖然它可能被更改爲一個平凡的常規one:d=dict(**d)

+0

最簡單的解決方案。 – Lanaru 2012-07-23 13:19:26

+0

@Lanaru:最簡單但是錯誤的解決方案,因爲你需要先轉置數組 – 2012-07-23 13:29:29

+0

問題是'(key1,value1)'它實際上是'('k1',[1,2,3,4]),但是對於'k1'我想要每個列表的第一個元素:'('k1',[1,5,9,13])' – julia 2012-07-23 13:29:40

7

您遇到問題explained in this answer:您的字典初始化爲同一個列表對象 resued for all values。只需使用

dict(zip(keys, zip(*data))) 

代替。這會將行列表轉換爲列列表,然後將鍵和列一起壓縮。

+0

感謝您回答如此之快,該行返回此字典: '{'k3':[9,10,11,12],'k2':[5,6,7,8],'k1':[1 ,2,3,4],'k4':[13,14,15,16]}'但我想要的是爲每列獲得一個列表的字典,而不是每行。 – julia 2012-07-23 13:26:29

+0

@ julia現在已經修復了這個問題 – jamylak 2012-07-23 13:27:24

+0

這可能沒有關係,但是這個解決方案會給你一個字典,它的值是'tuple's,而不是'list's。 – mgilson 2012-07-23 13:31:36

0

這應該工作:

keys = ['k1', 'k2', 'k3', 'k4'] 
data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]] 
mydict = {} 
for k in keys: 
    b[k] = [] 
    for l in data: 
     b[k].append(l[i]) 
    i += 1 

注意指數()是一個昂貴的功能。當你有一個龐大的數據集時不要使用它。在這種情況下增加一個變量。

編輯:不,它不!對不起,只是片刻

編輯:現在它的工作!

+0

爲什麼不僅僅使用'enumerate'(例如'for i,k in enumerate(keys):mydict [k] = keys [i]') – mgilson 2012-07-23 13:21:50

0
>>> keys = ['k1', 'k2', 'k3', 'k4'] 
>>> data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]] 
>>> dict(zip(keys, zip(*data))) 
{'k3': (3, 7, 11, 15), 'k2': (2, 6, 10, 14), 'k1': (1, 5, 9, 13), 'k4': (4, 8, 12, 16)} 

如果你真的需要列出:

>>> dict(zip(keys, map(list, zip(*data)))) 
{'k3': [3, 7, 11, 15], 'k2': [2, 6, 10, 14], 'k1': [1, 5, 9, 13], 'k4': [4, 8, 12, 16]} 

如果您正在使用python 2,zipmap回報list秒。如果您正在處理大型數據集,則可以使用itertools.izipitertools.imap以提高效率並避免創建中間列表。