映射python字典中的值
Posted
技术标签:
【中文标题】映射python字典中的值【英文标题】:Mapping over values in a python dictionary 【发布时间】:2012-08-27 01:57:14 【问题描述】:给定一个字典 k1: v1, k2: v2 ...
,如果我传递了一个函数f
,我想得到 k1: f(v1), k2: f(v2) ...
。
有没有这样的内置函数?还是我必须这样做
dict([(k, f(v)) for (k, v) in my_dictionary.iteritems()])
理想情况下我会写
my_dictionary.map_values(f)
或
my_dictionary.mutate_values_with(f)
也就是说,原始字典是否发生变异或创建副本对我来说无关紧要。
【问题讨论】:
编写示例的更好方法是dict((k, f(v)) for k, v in mydict.iteritems())
,即没有方括号,这将阻止通过生成器创建中间列表。
【参考方案1】:
没有这样的功能;最简单的方法是使用字典理解:
my_dictionary = k: f(v) for k, v in my_dictionary.items()
在 python 2.7 中,使用.iteritems()
方法而不是.items()
来节省内存。 dict 理解语法直到 python 2.7 才引入。
请注意,列表中也没有这种方法;您必须使用列表解析或 map()
函数。
因此,您也可以使用 map()
函数来处理您的 dict:
my_dictionary = dict(map(lambda kv: (kv[0], f(kv[1])), my_dictionary.iteritems()))
但这不是那么可读,真的。
【讨论】:
+1:这也是我会做的。dict(zip(a, map(f, a.values())))
稍微短一些,但我必须考虑它在做什么,并提醒自己是的,如果 dict 没有改变,键和值将以相同的顺序迭代。我根本不需要考虑 dictcomp 在做什么,所以这是正确的答案。
@chiborg:这是因为您现在不是一次性查找所有键值对,而是使用键数乘以 my_dictionary.__getitem__
调用。
请注意,由于 PEP3113(在 python 3.x 中实现)元组参数不再支持:lambda (k,v): (k, f(v))
将被重写为 lambda k_v: (k_v[0], f(k_v[1]))
之类的东西
为什么参数解包被拒绝了?这是如何改进?
来自 FP 语言,Python 看起来非常尴尬。【参考方案2】:
这些工具非常适合这种简单但重复的逻辑。
http://toolz.readthedocs.org/en/latest/api.html#toolz.dicttoolz.valmap
带你去你想去的地方。
import toolz
def f(x):
return x+1
toolz.valmap(f, my_list)
【讨论】:
【参考方案3】:您可以就地执行此操作,而不是创建新字典,这对于大型字典可能更可取(如果您不需要副本)。
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
【讨论】:
酷,你也许应该将mapdict
重命名为mutate_values_with
或其他东西,以明确你重写字典! :)
zip(d.keys(), d.values())
适用于更多版本,而不是 iteritems()
@ytpillai 'zip' 或理解进行复制,而不是就地更改值,这是我回答的目的。当副本没问题时,接受的答案是最好的答案。
抱歉,我没有意识到你想使用 items 方法。然而,另一个改进也是可能的(对于非 Python 2.7 用户)k:f(v) for k,v in iter(d.items())
通过创建迭代器节省空间【参考方案4】:
由于 PEP-0469 将 iteritems() 重命名为 items() 并且 PEP-3113 删除了 元组参数解包,因此在 Python 3.x 中您应该像这样编写 Martijn Pieters♦ answer:
my_dictionary = dict(map(lambda item: (item[0], f(item[1])), my_dictionary.items()))
【讨论】:
【参考方案5】:虽然我最初的答案没有抓住重点(通过尝试使用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 进行子类化,以赋予它所需的功能:在所有值上“映射”一个函数。
优点是该字典可用于存储原始数据,就像它是 dict
一样,同时根据请求通过回调转换任何数据。
当然,您可以随意命名类和函数(此答案中选择的名称受到 php 的 array_walk()
函数的启发)。
注意:try
-except
块和 return
语句都不是该功能所必需的,它们是为了进一步模仿 PHP 的 array_walk
的行为。
【讨论】:
这无法解决 OP 问题,因为不会为我们想要转换的现有键调用__missing__
方法,除非传递的工厂方法以某种方式使用原始字典作为后备,但由于这不是示例用法的一部分,我认为这是对手头问题的不令人满意的答案。
现有哪些键?
来自 OP:Given a dictionary k1: v1, k2: v2 ... ...
。也就是说,您已经有一个 dict
开头..
我想说我们都是对的;但我相信我们都错了。你是对的,我的回答没有回答这个问题。但不是因为你调用的原因。我只是错过了重点,给出了一种在给定[v1, v2, ...]
的情况下获得v1: f(v1), v2: f(v2), ...
的方法,而不是给出一个字典。我将编辑我的答案以更正。【参考方案6】:
为了避免从 lambda 内部进行索引,例如:
rval = dict(map(lambda kv : (kv[0], ' '.join(kv[1])), rval.iteritems()))
你也可以这样做:
rval = dict(map(lambda(k,v) : (k, ' '.join(v)), rval.iteritems()))
【讨论】:
这是第二个示例中 2 元组本身的巧妙操作。但是,它利用 lambda 中的自动元组解包,Python 3 不再支持。因此lambda(k,v)
将不起作用。见***.com/questions/21892989/…【参考方案7】:
刚刚遇到这个用例。我实现了gens's answer,添加了一种递归方法来处理也是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)
这在处理在 Python 2 中将字符串编码为字节的 json 或 yaml 文件时很有用
【讨论】:
【参考方案8】: 我的字典映射方式def f(x): return x+2
bill = "Alice": 20, "Bob": 10
d = map(lambda x: f(x),bill.values())
print('d: ',dict(d))
结果
: d: 22: 12
映射字典中的可迭代值
bills = "Alice": [20, 15, 30], "Bob": [10, 35]
d= map(lambda v: sum(v),bills.values())
g= dict(map(lambda v: (v[0],sum(v[1])),bills.items()))
# prints
print('d: ',dict(d))
print('g: ',g)
结果
d: 65: 45
g: 'Alice': 65, 'Bob': 45
【讨论】:
以上是关于映射python字典中的值的主要内容,如果未能解决你的问题,请参考以下文章