【问题标题】:How to extract dicts from list if these dicts have the same value for a specific key如果这些字典对特定键具有相同的值,如何从列表中提取字典
【发布时间】:2021-11-17 20:49:49
【问题描述】:

我有一个这样的字典列表

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”键不重复的所有字典?

【问题讨论】:

    标签: python list dictionary duplicates


    【解决方案1】:

    查找重复项的一种非常标准的方法是使用 Counter(您可以使用普通的 dict 和循环,但 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'}]
    

    【讨论】:

    • 谢谢你,它工作得很好!
    【解决方案2】:

    这是一个使用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'}]
    

    【讨论】:

    • 这太棒了!我想知道它是否会比我发布的基于Counter 的解决方案稍微高效一些,但是对列表进行排序要比迭代固定次数需要更长的时间。将itertools 函数组合成一个单行代码仍然是一个很酷的演示。
    • @Samwise 是的,我没想到它会更快,我只是喜欢玩 itertools(如果你喜欢,请查看我的其他答案:p)
    【解决方案3】:

    这种方法基本上创建了一个哈希映射,该映射提供了存在不同键值的索引列表。这里的关键是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'}]
    

    【讨论】:

      【解决方案4】:

      使用列表理解:

      >>> [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'}]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-30
        • 1970-01-01
        • 2020-11-10
        相关资源
        最近更新 更多