如果这些字典对特定键具有相同的值,如何从列表中提取字典

How to extract dicts from list if these dicts have the same value for a specific key

我有一个这样的字典列表

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

我的目标是提取此列表中键“b”具有相同“值”的所有字典。 在我的示例中它将是:

list_duplicates = [
    {
        "a": "1",
        "b": "2",
        "c": "3"
    },
    {
        "a": "4",
        "b": "2",
        "c": "6"
    },
    {
        "a": "7",
        "b": "8",
        "c": "9"
    },
    {
        "a": "13",
        "b": "8",
        "c": "15"
    }
]

我该如何执行此操作? 也许我可以使用反向逻辑:删除列表中“b”键不重复的所有字典?

查找重复项的一种非常标准的方法是使用 Counter(您可以使用普通的字典和循环,但 Counter 使它更容易),然后使用 Counter 过滤项目计数大于 1。

>>> my_list = [
...     {
...         "a": "1",
...         "b": "2",
...         "c": "3"
...     },
...     {
...         "a": "4",
...         "b": "2",
...         "c": "6"
...     },
...     {
...         "a": "7",
...         "b": "8",
...         "c": "9"
...     },
...     {
...         "a": "10",
...         "b": "11",
...         "c": "12"
...     },
...     {
...         "a": "13",
...         "b": "8",
...         "c": "15"
...     }
... ]
>>> from collections import Counter
>>> b_counts = Counter(d["b"] for d in my_list)
>>> list_duplicates = [d for d in my_list if b_counts[d["b"]] > 1]
>>> list_duplicates
[{'a': '1', 'b': '2', 'c': '3'}, {'a': '4', 'b': '2', 'c': '6'}, {'a': '7', 'b': '8', 'c': '9'}, {'a': '13', 'b': '8', 'c': '15'}]

这是使用 itertools.groupbyitertools.chainfilter 的功能版本:

from itertools import groupby, chain

list(chain(*filter(lambda x: len(x)>1,
                   (list(g) for k,g in groupby(sorted(lst, key=lambda d: d['b']),
                                               key=lambda d: d['b']))
              )))

解释:groupby 'b' 的值(为此字典必须按此键排序),然后 filter 每个大小的组,最后 chain输出形成一个列表。

注意。我将列表命名为 lst,以免与 list 内置

冲突

输出:

[{'a': '1', 'b': '2', 'c': '3'},
 {'a': '4', 'b': '2', 'c': '6'},
 {'a': '7', 'b': '8', 'c': '9'},
 {'a': '13', 'b': '8', 'c': '15'}]

这种方法基本上创建了一个散列图,提供了索引列表,其中存在不同的键值。这里的关键是lst中'b'对应的值。
所以基本上 countMap 看起来像这样:

{'2': [0, 1], '8': [2, 4], '11': [3]}

据此,我们可以创建输出列表,它仅附加原始列表中键值重复的索引。

countMap = {}
for i in range(len(lst)):
    val = lst[i]['b']
    if countMap.get(val) is not None:
        countMap[val].append(i)
    else:
        countMap[val] = [i]

output = []
for i in countMap.keys():
    if len(countMap[i]) > 1:
        for j in countMap[i]:
            output.append(lst[j])

print(output)

输出

[{'a': '1', 'b': '2', 'c': '3'}, {'a': '4', 'b': '2', 'c': '6'}, {'a': '7', 'b': '8', 'c': '9'}, {'a': '13', 'b': '8', 'c': '15'}]

有列表理解:

>>> [d for d in lst if len([di for di in lst if di["b"]==d["b"]])>1]
[{'a': '1', 'b': '2', 'c': '3'},
 {'a': '4', 'b': '2', 'c': '6'},
 {'a': '7', 'b': '8', 'c': '9'},
 {'a': '13', 'b': '8', 'c': '15'}]