问题:映射python字典中的值
给定一个字典,{ k1: v1, k2: v2 ... }
我想{ k1: f(v1), k2: f(v2) ... }
提供一个函数f
。
有没有这样的内置功能?还是我必须做
dict([(k, f(v)) for (k, v) in my_dictionary.iteritems()])
理想情况下,我只会写
my_dictionary.map_values(f)
要么
my_dictionary.mutate_values_with(f)
也就是说,对原始词典进行了突变还是创建副本对我来说都没有关系。
Given a dictionary { k1: v1, k2: v2 ... }
I want to get { k1: f(v1), k2: f(v2) ... }
provided I pass a function f
.
Is there any such built in function? Or do I have to do
dict([(k, f(v)) for (k, v) in my_dictionary.iteritems()])
Ideally I would just write
my_dictionary.map_values(f)
or
my_dictionary.mutate_values_with(f)
That is, it doesn’t matter to me if the original dictionary is mutated or a copy is created.
回答 0
没有这样的功能;最简单的方法是使用dict理解:
my_dictionary = {k: f(v) for k, v in my_dictionary.items()}
在python 2.7中,请使用.iteritems()
方法而不是.items()
节省内存。dict理解语法直到python 2.7才引入。
注意,列表上也没有这种方法。您将不得不使用列表推导或map()
函数。
这样,您也可以使用该map()
函数来处理字典:
my_dictionary = dict(map(lambda kv: (kv[0], f(kv[1])), my_dictionary.iteritems()))
但这确实不是那么可读。
There is no such function; the easiest way to do this is to use a dict comprehension:
my_dictionary = {k: f(v) for k, v in my_dictionary.items()}
In python 2.7, use the .iteritems()
method instead of .items()
to save memory. The dict comprehension syntax wasn’t introduced until python 2.7.
Note that there is no such method on lists either; you’d have to use a list comprehension or the map()
function.
As such, you could use the map()
function for processing your dict as well:
my_dictionary = dict(map(lambda kv: (kv[0], f(kv[1])), my_dictionary.iteritems()))
but that’s not that readable, really.
回答 1
回答 2
您可以就地执行此操作,而不是创建一个新的字典,这对于大型词典(如果您不需要副本)可能更可取。
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}
You can do this in-place, rather than create a new dict, which may be preferable for large dictionaries (if you do not need a copy).
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)
results in my_dictionary
containing:
{'a': 2, 'b': 3}
回答 3
由于PEP-0469将iteritems()重命名为items(),而PEP-3113删除了Tuple参数解包,因此在Python 3.x中,您应该这样编写Martijn Pieters♦答案:
my_dictionary = dict(map(lambda item: (item[0], f(item[1])), my_dictionary.items()))
Due to PEP-0469 which renamed iteritems() to items() and PEP-3113 which removed Tuple parameter unpacking, in Python 3.x you should write Martijn Pieters♦ answer like this:
my_dictionary = dict(map(lambda item: (item[0], f(item[1])), my_dictionary.items()))
回答 4
虽然我的原始答案没有指出要点(通过尝试使用defaultdict的工厂中的Accessing key解决方案来解决此问题),但我对其进行了重新设计以提出针对当前问题的实际解决方案。
这里是:
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子类化以赋予其所需的功能:在所有值上“映射”一个功能。
加号的是,该字典可用于存储原始数据,就好像它是一个dict
,同时根据请求通过回调转换任何数据。
当然,可以随意使用所需的名称来命名类和函数(此答案中选择的名称受PHP array_walk()
函数的启发)。
注意:try
– except
块和return
语句都不是功能必需的,它们可以进一步模仿PHP的行为array_walk
。
While my original answer missed the point (by trying to solve this problem with the solution to Accessing key in factory of defaultdict), I have reworked it to propose an actual solution to the present question.
Here it is:
class walkableDict(dict):
def walk(self, callback):
try:
for key in self:
self[key] = callback(self[key])
except TypeError:
return False
return True
Usage:
>>> d = walkableDict({ k1: v1, k2: v2 ... })
>>> d.walk(f)
The idea is to subclass the original dict to give it the desired functionality: “mapping” a function over all the values.
The plus point is that this dictionary can be used to store the original data as if it was a dict
, while transforming any data on request with a callback.
Of course, feel free to name the class and the function the way you want (the name chosen in this answer is inspired by PHP’s array_walk()
function).
Note: Neither the try
–except
block nor the return
statements are mandatory for the functionality, they are there to further mimic the behavior of the PHP’s array_walk
.
回答 5
为了避免从lambda内部进行索引,例如:
rval = dict(map(lambda kv : (kv[0], ' '.join(kv[1])), rval.iteritems()))
您也可以这样做:
rval = dict(map(lambda(k,v) : (k, ' '.join(v)), rval.iteritems()))
To avoid doing indexing from inside lambda, like:
rval = dict(map(lambda kv : (kv[0], ' '.join(kv[1])), rval.iteritems()))
You can also do:
rval = dict(map(lambda(k,v) : (k, ' '.join(v)), rval.iteritems()))
回答 6
刚遇到这个用例。我实现了gens的answer,添加了一种递归方法来处理也是dict的值:
def mutate_dict_in_place(f, d):
for k, v in d.iteritems():
if isinstance(v, dict):
mutate_dict_in_place(f, v)
else:
d[k] = f(v)
# Exemple handy usage
def utf8_everywhere(d):
mutate_dict_in_place((
lambda value:
value.decode('utf-8')
if isinstance(value, bytes)
else value
),
d
)
my_dict = {'a': b'byte1', 'b': {'c': b'byte2', 'd': b'byte3'}}
utf8_everywhere(my_dict)
print(my_dict)
这在处理在Python 2中将字符串编码为字节的json或yaml文件时非常有用
Just came accross this use case. I implemented gens’s answer, adding a recursive approach for handling values that are also dicts:
def mutate_dict_in_place(f, d):
for k, v in d.iteritems():
if isinstance(v, dict):
mutate_dict_in_place(f, v)
else:
d[k] = f(v)
# Exemple handy usage
def utf8_everywhere(d):
mutate_dict_in_place((
lambda value:
value.decode('utf-8')
if isinstance(value, bytes)
else value
),
d
)
my_dict = {'a': b'byte1', 'b': {'c': b'byte2', 'd': b'byte3'}}
utf8_everywhere(my_dict)
print(my_dict)
This can be useful when dealing with json or yaml files that encode strings as bytes in Python 2