切片字典列表并删除一个键

Slicing a list of dictionaries and removing one key

我有一个字典列表,如下所示:

l = [ { "a": 10, "b": 4, "c": 6 },
      { "a": 10, "b": 6, "c": 8 },
      { "a": 13, "b": 3, "c": 9 },
      { "a": 12, "b": 5, "c": 3 },
      { "a": 11, "b": 7, "c": 1 } ]

现在,我想将它切片并得到一个仅包含字典的列表,其中键 a 的值为 10,但从字典中删除键 a。喜欢下面的列表:

nl = [ { "b": 4, "c": 6 },
       { "b": 6, "c": 8 } ]

我可以通过处理 l 两次来做到这一点:

l[:] = [d for d in l if d.get("a") == 10]
nl = []
for c in l:
    del c["a"]
    nl.append(c)

是否有更直接的方法来完成此操作?

可能有更好的方法,但你可以做一个嵌套的字典理解:

[{k:d[k] for k in d if k!="a"} for d in l if d.get("a") == 10]

也许您可以使用 filter 和 map 函数来提高可读性和不变性。

示例(我没有测试):

l = [ { "a": 10, "b": 4, "c": 6 },
  { "a": 10, "b": 6, "c": 8 },
  { "a": 13, "b": 3, "c": 9 },
  { "a": 12, "b": 5, "c": 3 },
  { "a": 11, "b": 7, "c": 1 } ]

l_filtered = filter(lambda x: x.get('a') == 10, l)
l_filtered_without_a = map(lambda x: {'b': x.get('b'), 'c': x.get('c')}, l_filtered)

与 SO 上的 This question 类似,用于从字典中删除元素。剩下的就简单了。

[ {i:elem[i] for i in elem if i!="a"} for elem in l if elem["a"] == 10]

Returns

[{'b': 4, 'c': 6}, {'b': 6, 'c': 8}]

在我看来,你工作太辛苦了,没能把它写成单行本。创建两个空列表,并根据 a 键的值将每个字典附加到一个或另一个。

>>> l = [ { "a": 10, "b": 4, "c": 6 },
...       { "a": 10, "b": 6, "c": 8 },
...       { "a": 13, "b": 3, "c": 9 },
...       { "a": 12, "b": 5, "c": 3 },
...       { "a": 11, "b": 7, "c": 1 } ]
>>> l1 = []
>>> nl = []
>>> for d in l:
...    targetList = l1 if d.get('a') == 10 else nl
...    targetList.append(d)
>>> l1
[{'a': 10, 'c': 6, 'b': 4}, {'a': 10, 'c': 8, 'b': 6}]
>>> nl
[{'a': 13, 'c': 9, 'b': 3}, {'a': 12, 'c': 3, 'b': 5}, {'a': 11, 'c': 1, 'b': 7}]
>>>

我认为我有一个非常酷的单行代码,它应该非常快并且无论 a 是否在字典中都可以工作。它依赖于从字典中弹出 returns 键值(或 none 如果键不存在)以及删除条目的事实。请注意,它确实会发生变异 l

l = [ { "a": 10, "b": 4, "c": 6 },
      { "a": 10, "b": 6, "c": 8 },
      { "a": 13, "b": 3, "c": 9 },
      { "a": 12, "b": 5, "c": 3 },
      { "q": 12, "b": 5, "c": 3 },
      { "a": 11, "b": 7, "c": 1 } ]

ret = [d for d in l if "a" in d.keys() and d.pop("a") == 10]
print ret

>>[{'c': 6, 'b': 4}, {'c': 8, 'b': 6}]

可以用 map/filter

一行完成
res = [elem for elem in map(lambda x:{k:v for k,v in x.items() if k != 'a'}, [e for e in filter(lambda y:y.get('a') != 10,a)])]