【问题标题】:Mapping over values in a python dictionary映射python字典中的值
【发布时间】: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()),即没有方括号,这将阻止通过生成器创建中间列表。

标签: python dictionary map-function


【解决方案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) 将不起作用。见stackoverflow.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}
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-08-02
          • 1970-01-01
          • 1970-01-01
          • 2020-03-15
          • 1970-01-01
          • 2014-06-30
          相关资源
          最近更新 更多