【问题标题】:Filtering dictionaries and creating sub-dictionaries based on keys/values in Python?根据 Python 中的键/值过滤字典并创建子字典?
【发布时间】:2010-11-15 22:39:05
【问题描述】:

好吧,我被困住了,从这里需要一些帮助......

如果我有这样的主字典:

data = [ {"key1": "value1", "key2": "value2", "key1": "value3"},  
{"key1": "value4", "key2": "value5", "key1": "value6"}, 
{"key1": "value1", "key2": "value8", "key1": "value9"} ]

现在,我需要通过该字典来格式化一些数据,即:

for datadict in data:  
    for key, value in datadict.items():  
    ...filter the data...

现在,我将如何在同一个循环中以某种方式(如果可能......如果没有,请提出替代方案)检查某些键的值,如果这些值与我的预设匹配,那么我会将整个列表添加到另一个字典,从而在我根据某些键和值从这个主字典中走出来时有效地创建更小的字典?

所以,假设我想创建一个子词典,其中包含 key1 的值为“value1”的所有列表,对于上面的列表,它会给我这样的信息:

subdata = [ {"key1": "value1", "key2": "value2", "key1": "value3"},  
{"key1": "value1", "key2": "value8", "key1": "value9"} ]

【问题讨论】:

  • “这样的主词典”不正确。你有一个字典列表。
  • 而且字典键是唯一的,所以你不能用这样的重复键构造字典: {"key1": "value1", "key2": "value2", "key1": "值3"};结果是 {'key2': 'value2', 'key1': 'value3'}。如果您真的想要重复项,则需要一个列表,因此整体结构将是列表列表,或者字典值应该是元组或列表。

标签: python list dictionary filter


【解决方案1】:

这是一种不那么漂亮的方法。结果是一个生成器,但如果你真的想要一个列表,你可以通过调用list() 来包围它。基本上没关系。

谓词是一个函数,它为每个键/值对决定列表中的字典是否要剪切它。默认接受所有。如果字典中没有匹配的 k/v-pair 则被拒绝。

def filter_data(data, predicate=lambda k, v: True):
    for d in data:
         for k, v in d.items():
               if predicate(k, v):
                    yield d


test_data = [{"key1":"value1", "key2":"value2"}, {"key1":"blabla"}, {"key1":"value1", "eh":"uh"}]
list(filter_data(test_data, lambda k, v: k == "key1" and v == "value1"))
# [{'key2': 'value2', 'key1': 'value1'}, {'key1': 'value1', 'eh': 'uh'}]

【讨论】:

  • “不那么漂亮”?不同意。这是非常好的。
  • 谢谢你:)。我倾向于认为这样的楼梯功能很丑。
  • @Skurmedel:你的函数很优雅,很容易通过简单的步骤看出它是如何完成工作的;它使读者不必在头脑中解析复杂的单行代码。
  • 哇,这正是我想要的……我也不得不不同意“不那么漂亮”的评论。
【解决方案2】:

除去其他 cmets 和答案中已经指出的问题(多个相同的键不能在一个字典中,等等),我会这样做:

def select_sublist(list_of_dicts, **kwargs):
    return [d for d in list_of_dicts 
            if all(d.get(k)==kwargs[k] for k in kwargs)]

subdata = select_sublist(data, key1='value1')

【讨论】:

    【解决方案3】:

    答案太简单了,所以我想我们遗漏了一些信息。无论如何:

    result = []
    for datadict in data:
        for key, value in datadict.items():
            thefiltering()
    
        if datadict.get('matchkey') == 'matchvalue':
            result.append(datadict)
    

    另外,你的“主字典”不是字典而是列表。只是想澄清一下。

    【讨论】:

      【解决方案4】:

      受 Skurmedal 回答的启发,我将其拆分为一个递归方案来处理嵌套字典的数据库。在这种情况下,“记录”是主干上的子词典。谓词定义了我们要追踪的记录——那些匹配某些(键、值)对的记录,这些对可能嵌套得很深。

      def filter_dict(the_dict, predicate=lambda k, v: True):
          for k, v in the_dict.iteritems():
              if isinstance(v, dict) and _filter_dict_sub(predicate, v):
                  yield k, v
      
      def _filter_dict_sub(predicate, the_dict):
          for k, v in the_dict.iteritems():
              if isinstance(v, dict) and filter_dict_sub(predicate, v):
                  return True
              if predicate(k, v):
                  return True
          return False
      

      由于这是一个生成器,您可能需要使用dict(filter_dict(the_dict)) 进行包装以获得过滤字典。

      【讨论】:

        【解决方案5】:

        这是一个老问题,但由于某种原因,没有单一的语法答案:

        { k: v for k, v in <SOURCE_DICTIONARY>.iteritems() if <CONDITION> }
        

        例如:

        src_dict = { 1: 'a', 2: 'b', 3: 'c', 4: 'd' }
        predicate = lambda k, v: k % 2 == 0
        filtered_dict = { k: v for k, v in src_dict.iteritems() if predicate(k, v) }
        
        print "Source dictionary:", src_dict
        print "Filtered dictionary:", filtered_dict
        

        将产生以下输出:

        Source dictionary: {1: 'a', 2: 'b', 3: 'c', 4: 'd'}
        Filtered dictionary: {2: 'b', 4: 'd'}
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-05-17
          • 2012-05-14
          • 1970-01-01
          • 2020-02-06
          • 1970-01-01
          • 1970-01-01
          • 2019-02-23
          • 2016-08-14
          相关资源
          最近更新 更多