2012-09-01 114 views
142

鑑於字典{ k1: v1, k2: v2 ... }我想要{ k1: f(v1), k2: f(v2) ... }提供我通過一個函數f在python字典中的值映射

有沒有這樣的內置函數?或做我必須做的

dict([(k, f(v)) for (k, v) in my_dictionary.iteritems()]) 

理想的情況下,我只想寫

my_dictionary.map_values(f) 

my_dictionary.mutate_values_with(f) 

也就是說,如果原來的字典突變並不重要,我或一個副本被創建。

+2

書寫更好的辦法你的例子將是'dict((k,f(v))for k,v in mydict.iteritems())',即沒有方括號,這將阻止通過生成器創建中間列表。 – bereal

回答

205

沒有這樣的功能;要做到這一點最簡單的方法是使用字典理解:

my_dictionary = {k: f(v) for k, v in my_dictionary.items()} 

在Python 2.7版,而不是使用.items().iteritems()方法以節省內存。直到python 2.7才引入dict comprehension語法。

請注意,列表中也沒有這樣的方法;你必須使用列表理解或map()函數。

因此,您可以使用map()功能處理您的字典以及:

my_dictionary = dict(map(lambda kv: (kv[0], f(kv[1])), my_dictionary.iteritems())) 

但是這不是可讀的,真的。

+4

+1:這也是我會做的。 'dict(zip(a,map(f,a.values())))'稍微短一些,但我必須考慮它在做什麼,並提醒自己,是的,鍵和值按照相同的順序迭代如果字典不改變。我根本不必考慮dictcomp在做什麼,所以這是正確的答案。 – DSM

+0

@DSM:是的,拉鍊(adict,map(f,adict.values())))''技巧要求對隨機代碼閱讀器有太多的理解,更不用說增加所有關閉參數了! :-P –

+0

'my_dictionary中的k'的{{k:f(my_dictionary [k])'有點短,但有趣的是它也慢一些(用'timeit'計時,一個500項的詞典和'str()'爲'f')。不知道爲什麼。 – chiborg

13

可以就地做到這一點,而不是創建一個新的字典,這可能是最好的大的字典(如果你不需要複印件)。

def mutate_dict(f,d): 
    for k, v in d.iteritems(): 
     d[k] = f(v) 

my_dictionary = {'a':1, 'b':2} 
mutate_dict(lambda x: x+1, my_dictionary) 

結果my_dictionary包含:

{'a': 2, 'b': 3} 
+1

很酷,你可能應該將'mapdict'重命名爲'mutate_values_with'或其他東西,以便清楚地說明你重寫了字典! :) – Tarrasch

+0

@Tarrash同意;我重命名了這個函數。謝謝。 – gens

+1

'zip(d.keys(),d.values())'適用於更多版本,而不是'iteritems()' – ytpillai

2

雖然我原來的答覆錯過了點(由試圖解決這個問題,解決Accessing key in factory of defaultdict),我已經重新設計它提出了一個實際的解決方案目前的問題。

這就是:

class walkableDict(dict): 
    def walk(self, callback): 
    try: 
     for key in self: 
     self[key] = callback(self[key]) 
    except TypeError: 
     return False 
    return True 

用法:

>>> d = walkableDict({ k1: v1, k2: v2 ... }) 
>>> d.walk(f) 

的想法是繼承原來的字典給它所需的功能:「映射」在所有的值的功能。

重要的是,這個字典可以用來存儲原始數據,就好像它是一個dict,同時用請求通過回調來轉換任何數據。

當然,您可以隨心所欲地命名類和函數(在此答案中選擇的名稱受PHP的array_walk()函數啓發)。

注:無論是try - except塊也不是return語句是強制性的功能,他們在那裏進一步模仿的PHP的array_walk行爲。

+1

這不能解決OP問題,因爲'__missing__'方法不會被我們想要轉換的現有鍵調用,除非傳遞的工廠方法使用原點字典作爲後備方式,但由於這不是示例用法的一部分,所以我認爲這對於手頭問題來說是一個令人不滿意的答案。 – Kaos

+0

現有哪些密鑰? –

+0

從OP:'給出一個字典{k1:v1,k2:v2 ...} ...'。也就是說,你已經有了一個'dict'開頭.. – Kaos

2

由於PEP-0469其更名爲iteritems()項()和PEP-3113可以除去元組參數拆包,在Python 3.x的,你應該寫Martijn Pieters♦ answer這樣的:

my_dictionary = dict(map(lambda item: (item[0], f(item[1]), my_dictionary.items()))