2016-06-28 101 views
1

這是我的函數:Python中的多路頻率函數?

def freq(*var): 
    from functools import reduce 
    from operator import getitem 
    for c,i in enumerate(reversed(var)): 
     d={k:0 for k in set(i)} if c==0 else {k:d for k in set(i)} 
    for row in zip(*var): 
     *k,last_k=row 
     reduce(getitem,k,d)[last_k]+=1 

    return d 

var論點看起來像(['a','b','b','c'],['one','two','two','two'])

我試圖返回保存頻率計數嵌套的字典。所以導致d應該是這樣的:

{'a':{'one':1, 'two':0}, 'b':{'one':0, 'two':2}, 'c':{'one':0, 'two':1}} 

但是我的函數返回,這是錯誤的:

{'a': {'one': 1, 'two': 3}, 'b': {'one': 1, 'two': 3}, 'c': {'one': 1, 'two': 3}} 

任何想法,爲什麼?

+0

在給定的嵌套級別的每個字典都是相同的字典。 – user2357112

回答

2

的問題是,在d字典所有嵌套類型的字典是同一個對象。使用dict.copy()方法來解決問題,所以變化的線路:

d={k:0 for k in set(i)} if c==0 else {k:d for k in set(i)} 

d={k:0 for k in set(i)} if c==0 else {k:d.copy() for k in set(i)} 

將解決您的問題。查看更多關於Immutable vs Mutable typesHow do I pass a variable by reference?

祝你好運!

+0

@LMc它會回答你的問題嗎? –

0

您已經以某種方式初始化了d的值到同一字典。我無法自信地解決這個問題,因爲我沒有在這裏安裝Python3(臉紅)。不過,我認爲問題在於中間線的值:我認爲它將相同的默認字典插入到每個值中。嘗試創建一個新的空字典爲每次通過此迭代。

0

顯然,內部字典中引用相同的對象和一切都得到simultenously更新,如從enumerate環看出:

for c,i in enumerate(reversed(var)): 
    d={k:0 for k in set(i)} if c==0 else {k:d for k in set(i)} 
#           ^

在循環的第二次迭代中使用的內字典d是相同的對象。您可以使用d.copy()代替d爲每個密鑰創建多個副本。


但爲什麼經過上getitem使用reduce的所有麻煩。你的代碼部分很難調試。

您可以使用您一個Counter對象實現同樣的事情拉鍊項目:

from collections import Counter 

var = ['a','b','b','c'],['one','two','two','two'] 

c = Counter(zip(*var)) 
d = {k[0]: {j: v if j in k else 0 for j in set(var[1])} for k,v in c.items()} 
print(d) 
# {'b': {'two': 2, 'one': 0}, 'c': {'two': 1, 'one': 0}, 'a': {'two': 0, 'one': 1}} 
+0

'var'可能有一個或多個元素。在這裏,我使用了兩個,但它可能會更多或更少。 – LMc

+0

通過在dict理解中創建更深的嵌套,可以擴展代碼。你可以通過將它重構爲一個循環,使其認識到'var'中的元素數量,使其成爲一個動態。 –