【问题标题】:Python list comprehension for dictionaries in dictionaries?字典中字典的Python列表理解?
【发布时间】:2011-03-14 23:03:03
【问题描述】:

我刚刚了解了列表推导,这是在一行代码中获取数据的一种非常快速的方法。但有些事情困扰着我。

在我的测试中,列表中有这样的字典:

[{'y': 72, 'x': 94, 'fname': 'test1420'}, {'y': 72, 'x': 94, 'fname': 'test277'}]

列表理解 s = [ r for r in list if r['x'] > 92 and r['x'] < 95 and r['y'] > 70 and r['y'] < 75 ] 完美地工作(事实上,它是这一行的结果)

无论如何,我后来意识到我并没有真正在我的其他项目中使用列表,我使用的是字典。像这样:

{'test1420': {'y': '060', 'x': '070', 'fname': 'test1420'}}

这样我就可以简单地用var['test1420'] = ...编辑我的字典

但是列表推导对此不起作用! 而且我不能以这种方式编辑列表,因为你不能分配这样的索引。

还有其他方法吗?

【问题讨论】:

  • 列表推导可能很酷,但不要过火。没有严格的规则反对巨大的理解,但对于它的价值,谷歌的 Python 样式指南建议不要任何过于复杂的东西:google-styleguide.googlecode.com/svn/trunk/…

标签: python list dictionary list-comprehension


【解决方案1】:

你可以这样做:

s = dict([ (k,r) for k,r in mydict.iteritems() if r['x'] > 92 and r['x'] < 95 and r['y'] > 70 and r['y'] < 75 ])

这需要一个你指定的字典并返回一个“过滤”的字典。

【讨论】:

  • 工作方式与 Tryptich 的解决方案相同,但使用 iteritems 确实更快。谢谢!
  • 如果您将[] 转换为(),则可以更快地完成此操作,因为 dict 可以将生成器作为参数(如果生成器表达式是唯一的参数,就像在这种情况下甚至 @ 987654324@可以省略)
  • 对于 python3 ,使用 dict.items() 而不是 dict.iteritems()
  • 如果您不需要保留密钥,您也可以使用dict.values() 并在此基础上进行规则列表理解。
【解决方案2】:

如果dct

{'test1420': {'y': '060', 'x': '070', 'fname': 'test1420'},
 'test277': {'y': 72, 'x': 94, 'fname': 'test277'},}

也许你正在寻找类似的东西:

[ subdct for key,subdct in dct.iteritems() 
  if 92<subdct['x']<95 and 70<subdct['y']<75 ]

Python 允许你链接不等式:

92<dct[key]['x']<95

而不是

if r['x'] > 92 and r['x'] < 95

还要注意,上面我已经写了一个列表理解,所以你会得到一个列表(在这种情况下,是 dicts)。

在Python3中也有dict comprehensions这样的东西:

{ n: n*n for n in range(5) } # dict comprehension
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

在 Python2 中相当于

dict( (n,n*n) for n in range(5) )

我不确定你是在寻找字典列表还是字典的字典,但如果你理解上面的例子,很容易修改我的答案以获得你想要的。

【讨论】:

    【解决方案3】:

    听起来你想要这样的东西:

    my_dict = {'test1420': {'y': '060', 'x': '070', 'fname': 'test1420'},
               'test277' : {'y': '072', 'x': '094', 'fname': 'test277'}}
    
    
    new_dict = dict((k,v) for k,v in my_dict.items() 
                        if 92 < int(v['x']) < 95 and 70 < int(v['y']) < 75)
    

    关于此代码的一些注释:

    1. 我正在使用生成器表达式 而不是列表理解
    2. Python 让您可以组合不等式 测试为low &lt; value &lt; high
    3. dict() 构造函数采用可迭代对象 键/值元组创建一个 字典

    【讨论】:

    • 这工作,并且看起来,与 adamk 的解决方案相同。然而使用 iteritems 比这个快很多。两者都比常规列表理解慢,但是:P 感谢您的组合提示!
    【解决方案4】:

    在 Python 3 中,您可以使用 dict 理解,这可能是一个更短的解决方案:

    {key_expression(item) : value_expression(item) for item in something if condition}
    
    1. 如果您想像原始问题一样过滤字典:

      mydict = {'test1': {'y':  60},'test2': {'y':  70},'test3': {'y':  80}}
      s = {k : r for k,r in mydict.items() if r['y'] < 75 }
      > {'test1': {'y': 60}, 'test2': {'y': 70}}
      
    2. 或者我们甚至可以从列表或范围中创建一些东西。例如。如果我们想要一个包含所有奇数平方数的字典:

      {i : i**2 for i in range(11) if i % 2 == 1}
      > {1: 1, 3: 9, 5: 25, 7: 49, 9: 81}
      

    【讨论】:

      【解决方案5】:

      您可以使用d.values() 获取字典 d 的值列表。您的列表理解应该可以使用它,尽管我有点不清楚您到底想要输出什么。

      【讨论】:

        【解决方案6】:

        还有其他方法吗?

        为什么不考虑使用一些轻量级的对象呢?

        您可以仍然使用列表推导来收集或过滤对象,并在清晰度/可扩展性方面获得很多。

        >>> class Item(object):
        ...     def __init__(self, x, y, name):
        ...         self.x = x
        ...         self.y = y
        ...         self.name = name
        ... 
        >>> list_items = []
        >>> list_items.append(Item(x=70, y=60, name='test1420'))                        
        >>> list_items.append(Item(x=94, y=72, name='test277'))                         
        >>> items_matching = [item for item in list_items 
                              if 92 < item.x < 95 and 70 < item.y < 75]
        >>> for item in items_matching:
        ...     print item.name
        ... 
        test277
        >>> first_item = items_matching[0]
        >>> first_item.x += 50
        >>> first_item.x
        144
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-10-18
          • 1970-01-01
          • 2022-11-22
          • 2023-02-15
          • 2018-03-18
          相关资源
          最近更新 更多