【问题标题】:python filter list of dictionaries based on key valuepython根据键值过滤字典列表
【发布时间】:2015-05-17 01:50:30
【问题描述】:

我有一个字典列表,每个字典都有一个(比方说)“类型”键,其值可以是'type1''type2' 等。我的目标是将这些字典过滤到一个列表中相同的词典,但只有特定“类型”的词典。我想我真的在为list/dictionary 理解而苦苦挣扎。

所以示例列表如下所示:

exampleSet = [{'type':'type1'},{'type':'type2'},{'type':'type2'}, {'type':'type3'}]

我有一个键值列表。比如说:

keyValList = ['type2','type3']

预期的结果列表如下所示:

expectedResult = [{'type':'type2'},{'type':'type2'},{'type':'type3'}]

我知道我可以使用一组 for 循环来做到这一点。我知道必须有一个更简单的方法。我发现这个问题有很多不同的风格,但没有一个真正符合要求并回答了这个问题。我会尝试发布答案……但它们并没有那么令人印象深刻。可能最好让它保持开放式。任何帮助将不胜感激。

【问题讨论】:

    标签: python list python-2.7 dictionary


    【解决方案1】:

    你可以试试list comp

    >>> exampleSet = [{'type':'type1'},{'type':'type2'},{'type':'type2'}, {'type':'type3'}]
    >>> keyValList = ['type2','type3']
    >>> expectedResult = [d for d in exampleSet if d['type'] in keyValList]
    >>> expectedResult
    [{'type': 'type2'}, {'type': 'type2'}, {'type': 'type3'}]
    

    另一种方法是使用filter

    >>> list(filter(lambda d: d['type'] in keyValList, exampleSet))
    [{'type': 'type2'}, {'type': 'type2'}, {'type': 'type3'}]
    

    【讨论】:

    • 哪个最快?
    • @DarkSkull 我不确定,因为我没有测试过。随意对其进行测试并根据您的发现发布答案。 :)
    • 如果keys 不同怎么办?不只是单身type
    【解决方案2】:

    使用filter,或者如果exampleSet 中的字典数量过多,请使用itertools 模块的ifilter。它会返回一个迭代器,而不是一次用整个列表填满系统的内存:

    from itertools import ifilter
    for elem in ifilter(lambda x: x['type'] in keyValList, exampleSet):
        print elem
    

    【讨论】:

    • 注意:对于 Python3,内置的 filter() 函数返回一个迭代器; itertools.ifilter 已被删除。
    【解决方案3】:

    尝试了这篇文章中的几个答案,我测试了每个答案的性能。

    我最初的猜测是,list comprehension is way fasterfilterlist 方法排在第二位,pandas 排在第三位。

    定义变量:

    import pandas as pd
    
    exampleSet = [{'type': 'type' + str(number)} for number in range(0, 1_000_000)]
    
    keyValList = ['type21', 'type950000']
    


    第一 - list comprehension

    %%timeit
    expectedResult = [d for d in exampleSet if d['type'] in keyValList]
    

    每个循环 60.7 ms ± 188 µs(平均值 ± 标准偏差,7 次运行,每次 10 个循环)

    第二个 - filterlist

    %%timeit
    expectedResult = list(filter(lambda d: d['type'] in keyValList, exampleSet))
    

    每个循环 94 毫秒 ± 328 微秒(平均值 ± 标准偏差,7 次运行,每次 10 次循环)

    第三个 - pandas

    %%timeit
    df = pd.DataFrame(exampleSet)
    expectedResult = df[df['type'].isin(keyValList)].to_dict('records')
    

    每个循环 336 毫秒 ± 1.84 毫秒(平均值 ± 标准偏差,7 次运行,每个循环 1 个)


    附带说明,使用pandas 处理dict 不是一个好主意,因为pandas.DataFrame 基本上是一个更消耗内存的dict,如果你不是最后要使用数据框效率很低。

    【讨论】:

      【解决方案4】:

      通用方法filter the list of dictionaries based on key-value pairs

      def get_dic_filter_func(**kwargs):
          """Func to be used for map/filter function,
          returned func will take dict values from kwargs keys and compare resulted dict with kwargs"""
          def func(dic):
              dic_to_compare = {k: v for k, v in dic.items() if k in kwargs}
              return dic_to_compare == kwargs
          return func
      
      
      def filter_list_of_dicts(list_of_dicts, **kwargs):
          """Filter list of dicts with key/value pairs
          in result will be added only dicts which has same key/value pairs as in kwargs """
          filter_func = get_dic_filter_func(**kwargs)
          return list(filter(filter_func, list_of_dicts))
      

      测试用例 / 使用方法

          def test_filter_list_of_dicts(self):
              dic1 = {'a': '1', 'b': 2}
              dic2 = {'a': 1, 'b': 3}
              dic3 = {'a': 2, 'b': 3}
              the_list = [dic1, dic2, dic3]
      
              self.assertEqual([], filter_list_of_dicts(the_list, x=1))
              self.assertEqual([dic1], filter_list_of_dicts(the_list, a='1'))
              self.assertEqual([dic2], filter_list_of_dicts(the_list, a=1))
              self.assertEqual([dic2, dic3], filter_list_of_dicts(the_list, b=3))
      

      【讨论】:

        【解决方案5】:

        这种类型的过滤在 Pandas 中很容易实现,尤其是在很多情况下,字典列表作为 Pandas 数据框的表现更好。

        import pandas as pd
        
        exampleSet = [{'type':'type1'}, {'type':'type2'}, {'type':'type2'}, {'type':'type3'}]
        keyValList = ['type2', 'type3']
        
        df = pd.DataFrame(my_list)
        df[df['type'].isin(keyValList)]
        

        结果:

            type
        1   type2
        2   type2
        3   type3
        

        并按照 OP 的要求以字典形式取回:

        expectedResult = df[df['type'].isin(keyValList)].to_dict('records')
        # the result will be [{'type': 'type2'}, {'type': 'type2'}, {'type': 'type3'}]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-02-06
          • 1970-01-01
          • 2017-04-22
          • 2020-09-11
          • 1970-01-01
          • 2012-05-14
          • 2019-12-27
          • 2023-01-14
          相关资源
          最近更新 更多