【问题标题】:List Comprehension of Lists Nested in Dictionaries嵌套在字典中的列表的列表理解
【发布时间】:2013-11-15 14:33:57
【问题描述】:

我有一个字典,其中每个值都是一个列表,如下所示:

dictA = {1:['a','b','c'],2:['d','e']}

很遗憾,我无法更改此结构来解决我的问题

我想将列表的所有条目收集到一个列表中,如下所示:

['a','b','c','d','e']

此外,我只想在 if 块中执行一次。由于我只想做一次,我不想将它存储到中间变量中,所以很自然地,列表推导是要走的路。但是怎么做?我的第一个猜测,

[dictA[key] for key in dictA.keys()]

产量,

[['a','b','c'],['d','e']]

这不起作用,因为

'a' in  [['a','b','c'],['d','e']]

产生False。我尝试过的所有其他内容都使用了某种非法语法。

我该如何进行这样的理解?

【问题讨论】:

    标签: python list python-2.7 dictionary list-comprehension


    【解决方案1】:

    用简单的代码来理解这一点可能会有所帮助

    ListA=[]
    dictA = {1:['a','b','c'],2:['d','e']}
    for keys in dictA:
        for values in dictA[keys]:
            ListA.append(values)
    

    【讨论】:

      【解决方案2】:

      循环遍历返回的列表too(直接循环遍历字典也会给你键):

      [value for key in dictA for value in dictA[key]]
      

      或者更直接地使用dictA.itervalues():

      [value for lst in dictA.itervalues() for value in lst]
      

      列表推导式让您可以嵌套循环;阅读上面的循环,就好像它们以相同的顺序嵌套一样:

      for lst in dictA.itervalues():
          for value in lst:
              # append value to the output list
      

      或者使用itertools.chain.from_iterable():

      from itertools import chain
      
      list(chain.from_iterable(dictA.itervalues()))
      

      后者采用一系列序列并让您循环遍历它们,就好像它们是一个大列表一样。 dictA.itervalues() 为您提供一系列列表,chain() 将它们放在一起,以便 list() 迭代并从中构建一个大列表。

      如果您所做的只是测试所有值之间的成员资格,那么您真正想要的是一种简单的方法来遍历所有值,并针对每个值测试您的值,直到找到一场比赛。 any() function 加上合适的生成器表达式就是这样做的:

      any('a' in lst for lst in dictA.itervalues())
      

      一旦dictA 中的任何值列出'a',这将返回True,并尽早停止循环遍历.itervalues()

      【讨论】:

      • 当然,一旦我接受了您的回复,问题就会变得更加复杂。我现在需要从两个单独的字典中的嵌套列表中提取所有名称。我可以为此使用zip() 吗?所以你的解决方案是any('a' in lst for lst in zip(dictA.itervalues(),dictB.itervalues())
      • @wnnmaw:再次使用itertools.chain()any('a' in lst for lst in chain(dictA.itervalues(), dictB.itervalues())zip() 做了完全不同的事情。
      【解决方案3】:

      你可以做一些像..

      output_list = []

      [ output_list.extend(x) for x in {1:['a','b','c'],2:['d','e']}.values()]

      output_list 将是 ['a', 'b', 'c', 'd', 'e']

      【讨论】:

      • 不要使用列表推导的副作用。您在这里浪费了内存和 CPU 周期,因为您构建了一个 None 值列表。
      【解决方案4】:

      如果您实际上是在检查成员资格(您的 a in... 示例),您可以将其重写为:

      if any('a' in val for val in dictA.itervalues()):
          # do something
      

      这样可以避免在实际上不需要时将列表展平。

      【讨论】:

      • 一旦找到匹配项,它也会短路(退出)。
      • 糟糕,我没有看到您也提出了这种方法。我不是故意在这里看起来像小偷,对不起!
      • @Martijn 不用担心... :) (虽然我根据时间戳赢了 :P)
      • 那是因为我的最后一次编辑刚刚过了上一个宽限期。 :-P 我并没有声称要先发帖。 :-)
      【解决方案5】:

      在这种特殊情况下,您可以只使用嵌套推导:

      [value for key in dictA.keys() for value in dictA[key]]
      

      但总的来说,如果您已经知道如何将某些内容转换为嵌套列表,则可以使用 chain.from_iterable 展平任何嵌套的迭代:

      itertools.chain.from_iterable(dictA[key] for key in dictA.keys())
      

      这会返回一个迭代器,而不是一个列表;如果您需要一个列表,只需明确执行:

      list(itertools.chain.from_iterable(dictA[key] for key in dictA.keys()))
      

      作为旁注,for key in dictA.keys()for key in dictA 做同样的事情,除了在旧版本的 Python 中,它会浪费时间和内存来制作额外的键列表。正如the documentation 所说,dict 上的iteriterkeys 相同。

      因此,在上述所有版本中,最好只使用in dictA

      【讨论】:

      • @MartijnPieters:只是因为他在最初的问题中有它;我打算添加一个解释为什么不需要它。
      猜你喜欢
      • 2021-02-23
      • 1970-01-01
      • 2021-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-23
      • 1970-01-01
      • 2018-08-23
      相关资源
      最近更新 更多