映射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 一样,同时根据请求通过回调转换任何数据。

当然,您可以随意命名类和函数(此答案中选择的名称受到 phparray_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字典中的值的主要内容,如果未能解决你的问题,请参考以下文章

使用宽松字典映射列中的值

python字典

Python基础数据类型——字典

Python字典_术语

Python字典集合结构详解

《转》python学习字典