【问题标题】:Remove "None" from iteration in a dictionary从字典中的迭代中删除“无”
【发布时间】:2020-01-17 01:32:44
【问题描述】:

我有一个包含各种键和值的字典列表。我正在尝试根据键对其进行分组

from itertools import chain, zip_longest 

data = [
    {'a': 2, 'b': 4, 'c': 3, 'd': 2},   
    {'b': 2, 'c': 2, 'd': 5, 'e': 4, 'f': 1},
    {'a': 2, 'd': 2, 'e': 6, 'f': 5, 'g': 12},
    {'b': 2, 'd': 2, 'e': 6, 'f': 6},
    {'c': 5, 'e': 33, 'g': 21, 'h': 56, 'i': 21}
    ]

print(type(data))

bar ={
    k: [d.get(k) for d in data]
    for k in chain.from_iterable(data)
}

print(bar)

我的输出:

{'a': [2, None, 2, None, None], 'b': [4, 2, None, 2, None], 
'c': [3, 2, None, None, 5], 'd':[2, 5, 2, 2, None], 'e': [None, 4, 6, 6, 33], 
'f': [None, 1, 5, 6, None], 'g': [None, None, 12, None, 21], 
'h': [None, None, None, None, 56], 'i': [None, None, None, None, 21]}

我不想在值中显示“无”

期望的输出:

 {'a': [2, 2], 'b': [4, 2, 2], 'c': [3, 2, 5], 'd':[2, 5, 2, 2], 'e': [4, 6, 6, 33], 
'f': [1, 5, 6], 'g': [1221], 'h': [56], 'i': [21]}

我也尝试使用过滤功能,但没有成功。关于如何删除无的任何指导?

Code

【问题讨论】:

  • 您可以将列表理解(在您的字典中)更改为 [d.get(k) for d in data if d.get(k) is not None]
  • k: [d[k] for d in data if k in d]
  • @chirs: 是的,提供项目k 的值不是False 或其他虚假值!
  • @tomjn 或 [val := d.get(k) for d in data if val] 在 Python 3.8 中,所以 .get 不会被调用两次 ;)
  • @DeepSpace 我想到了。认为在测试版结束之前最好不要给出 3.8 个答案;)

标签: python python-3.x dictionary


【解决方案1】:

试试this:

from operator import is_not
from functools import partial

{ k: list(filter(partial(is_not, None), v)) for k, v in d.items() }

输入: {'x': [0, 23, 234, 89, None, 0, 35, 9] }

输出: {'x': [0, 23, 234, 89, 0, 35, 9]}

【讨论】:

    【解决方案2】:

    不要使用get,如果密钥不存在则返回None,只需使用d[k],但首先检查是否k in d。另外,我建议不要使用chain,因为这会计算许多列表两次或更多次,每次都会覆盖先前创建的列表,因为多个字典中存在许多键。相反,您可以迭代所有键的 set

    >>> {k: [d[k] for d in data if k in d]
    ...  for k in set(k for d in data for k in d)}
    ...
    {'a': [2, 2], 'b': [4, 2, 2],
     'c': [3, 2, 5], 'd': [2, 5, 2, 2],
     'e': [4, 6, 6, 33], 'f': [1, 5, 6],
     'g': [12, 21], 'h': [56], 'i': [21]}
    

    【讨论】:

      【解决方案3】:

      如果你想使用你的代码,你可以这样做:

      bar ={
          k: [d.get(k) for d in data if d.get(k) != None]
          for k in chain.from_iterable(data)
      }
      
      print(bar)
      

      输出:

      {'a': [2, 2], 'b': [4, 2, 2], 'c': [3, 2, 5], 'd': [2, 5, 2, 2], 'e': [4, 6, 6, 33], 'f': [1, 5, 6], 'g': [12, 21], 'h': [56], 'i': [21]}
      

      【讨论】:

      • k: [d[k] for d in data if k in d] 呢?
      • 也是解决方案之一! :) @tobias_k
      【解决方案4】:

      提供的大多数解决方案都专注于保持 OP 方法具有复杂的理解力。我认为在这种情况下,有必要将循环拆分为不同的行,而不是使用理解。

      data = [...]
      
      bar = {}
      for my_dict in data:
         for key, value in my_dict.items():
            bar.setdefault(key, []).append(value)
      
      print(bar)
      

      【讨论】:

      • 是的,这也是我的首选解决方案。不过,OP 明确要求使用filter。看起来像一个 x/y 问题。
      【解决方案5】:

      字典的get 函数将在它们的键不存在时返回None。您可以简单地使用if 条件来确保该值存在。

      bar = {k: [d[k] for d in data if d.get(k) is not None] for k in chain.from_iterable(data)}
      

      如果您的字典非常大,在值中包含大量 Nones,则双重查找的成本会很高。所以你可以使用过滤器。

      bar = {k: list(filter(None, [d.get(k) for d in data])) for k in chain.from_iterable(data)}
      

      【讨论】:

      • 这可行,但每个元素都有双重查找。
      • OP 的另一个选项是重新遍历整个字典并从每个列表中过滤掉 None 值。这样会更好。
      • 取决于查找的成本,这取决于dict 的大小。过滤掉Nones 可能会更便宜。
      【解决方案6】:

      您可以使用filter(None, x) 删除Nones:

      filter(None, [3, 4, None, 2, 7, None, 1])
      [3, 4, 2, 7, 1]
      

      要对 dict 的所有值都使用它,请使用理解:

      { k: filter(None, v) for k, v in d.items() }
      

      (在 Python 2 中使用 .iteritems()。)

      请记住,在 Python 3 中,filter 函数会生成可以廉价迭代的惰性过滤器对象。要将它们转换为lists,只需使用list(filter(...))

      但最好不要一开始就引入None 值:

      r = {}
      for d in data:
        for k, v in d.items():
          r.setdefault(k, []).append(v)
      print(r)
      

      【讨论】:

      • { k: list(filter(None, v)) for k, v in d.items() } 可能更好,所以值将是列表而不是 filter 对象
      • @DeepSpace 这在许多情况下可能很有用,但总的来说,我更喜欢尽可能长时间地保留惰性迭代器,因为它们更便宜,以防并非所有元素都真正需要或所有元素都需要但不是同时(然后节省内存)。正如您所演示的,将它们转换为 lists 仍然是可能的。
      • @DeepSpace 我更愿意让他们了解并留给他们选择和责任。
      • 但你没有。答案没有说明这些值不再是列表
      猜你喜欢
      • 1970-01-01
      • 2011-07-20
      • 1970-01-01
      • 2014-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多