【问题标题】:How to quickly access all values corresponding to a specific second level key regardless of first level key in a Python dictionary?无论Python字典中的第一级键如何,如何快速访问与特定第二级键对应的所有值?
【发布时间】:2013-02-05 08:59:39
【问题描述】:

我有一个 Python 字典,例如:

Mydict = {'a': {'y': 1, 'x': 5}, 'b': {'y': 10, 'x': 8}}

有没有什么快速的方法可以访问键对应的值:'x',在这种情况下是二级键,不管一级键是什么?

我知道可以使用 for 循环来完成,例如:

mylist=[]
for k in Mydict.keys():
    mylist.append(Mydict[k]['x'])

但是有没有快速的单行方法呢?

【问题讨论】:

    标签: python dictionary


    【解决方案1】:

    使用list-comprehension

    mylist = [v['x'] for v in Mydict.values()]
    

    由于您不需要外部键,您只需遍历内部字典,并获得所需的 'x' 值。

    注意:这只有在每个内部字典都有一个 'x' 键时才有效,可以肯定的是,为了最大限度地减少错误,您可以这样做:

    mylist = [v.get('x', None) for v in Mydict.values()]
    

    这将起到相同的作用,只有当字典中没有 'x' 键时,它才会返回 None 而不是 KeyError 异常。

    关于时间安排,以及哪种方法最好,请查看Thorsten Kranz的答案

    【讨论】:

      【解决方案2】:

      为了完整性:map 通常是列表理解的一个很好的替代方案,例如

      mylist = map(lambda v: v['x'], Mydict.values())
      

      mylist = map(lambda k: Mydict[k]['x'], Mydict)
      

      这通常取决于你喜欢什么。

      编辑:

      随着性能的提高,这里对 1,000,000 次重复进行快速比较:

      import timeit
      
      Mydict = {'a': {'y': 1, 'x': 5}, 'b': {'y': 10, 'x': 8}}
      
      def list_append(d):
          mylist=[]
          for k in d.keys():
              mylist.append(d[k]['x'])
      
      def list_comprehension_values(d):
          return [v['x'] for v in d.values()]
      
      def list_comprehension_keys(d):
          return [d[k]['x'] for k in d]
      
      def map_values(d):
          return map(lambda v: v['x'], d.values())
      
      def map_keys(d):    
          return map(lambda k: d[k]['x'], d)
      
      for method_name in ["list_append",
                          "list_comprehension_values",
                          "list_comprehension_keys",
                          "map_values",
                          "map_keys"]:
          t = timeit.timeit(method_name + "(Mydict)",
                            "from __main__ import Mydict, " + method_name, 
                            number=1000000)
          print "%s: %.2f seconds" % (method_name, t)
      

      结果:

      list_append: 0.95 seconds
      list_comprehension_values: 0.56 seconds
      list_comprehension_keys: 0.47 seconds
      map_values: 1.02 seconds
      map_keys: 1.01 seconds
      

      *编辑 2 *

      对于更大的字典

      Mydict = dict(zip(range(10000), 
                    [{'x' : random.randint(0,10), 'y' : random.randint(0,10)} 
                        for i in range(10000)]))
      

      且重复次数少(number=10000),数值不同:

      list_append: 16.41 seconds
      list_comprehension_values: 6.00 seconds
      list_comprehension_keys: 9.62 seconds
      map_values: 15.23 seconds
      map_keys: 18.42 seconds
      

      所以在这里节省键查找会更好。

      【讨论】:

      • 偏好很重要,可读性也很重要,但速度和效率也很重要。当迭代内部字典时,您可以节省查找速度,这比迭代键然后每次查找它们要快。另外 - 正如我的回答一样,可能应该使用 dict.get(key, default) 而不仅仅是访问它。
      • 我也很惊讶直接访问值并不比每次迭代键并查找值更快
      • 好吧,为了反驳你的论点,这是在一个非常小的子集上测试的。给定更大的数据集,更快的实现可能会有所不同。但是我会承认,对于较小的 dicts,获取键列表然后查看 1 或 2 个值的小 dicts 可能会更快......我希望你明白我的观点,即使用数百个外部和内部键的 dicts跳过外部字典并直接进入会更快。 - 即使使用较小的数据集,差异也不会像其他人所说的那样快“两倍”。
      • 你是对的,对于更大的字典,你的方法更快。
      【解决方案3】:

      使用列表理解

      mylist = [Mydict[k]['x'] for k in Mydict]
      

      请注意,遍历 Mydict 会自动遍历键,因此无需遍历 Mydict.keys()

      【讨论】:

      • 您的方法是建议选项中最快的。
      • ...但仅适用于小型词典
      【解决方案4】:

      列表推导只需一行,速度几乎是原来的两倍:

      mylist = [mydict[k]['x'] for k in mydict]
      

      【讨论】:

      • 为什么没有更快? AFAIK 更快,请解释一下?
      • 我们还是 O(len(mydict))。当然,循环开销要小一些。
      • 列表推导以比原生 python 更有效的方式实现。而且速度更快,你可以自己检查,不信。
      • 好吧,我太理论了。
      • 列表理解的速度是原来的两倍,而且您使用键的方法甚至比直接访问值还要快 - 请参阅我的答案中的测试。
      猜你喜欢
      • 2018-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-16
      • 2021-10-16
      • 2020-12-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多