【问题标题】:How to filter and remove dict elements based on a value threshold?如何根据值阈值过滤和删除 dict 元素?
【发布时间】:2020-12-03 16:31:31
【问题描述】:

我的列表中有几个具有这种结构的字典:

[{'store': 'walmart',
  'store_id': 0,
  'store_info': {'grapes': {'availability': {'No': 1, 'Yes': 1}},
   'tomatoes': {'availability': {'No': 5, 'Yes': 6}},
   'oranges': {'availability': {'No': 2, 'Yes': 2}},
   'bottled water': {'availability': {'No': 10, 'Yes': 5}},
   "india's mangos": {'availability': {'No': 3, 'Yes': 5}},
   'water melon': {'availability': {'No': 2, 'Yes': 2}},
   'lemons': {'availability': {'No': 2, 'Yes': 3}},
   'kiwifruit': {'availability': {'No': 4, 'Yes': 2}},
   'pineapple': {'availability': {'No': 5, 'Yes': 20}},
   'total_yes': 23,
   'total_no': 23,
   'total': 46,
   'id': [3, 4, 6, 2, 1, 6, 1, 4, 2]}},
{'store': 'Costco',
  'store_id': 24,
  'store_info': {'papaya': {'availability': {'No': 1, 'Yes': 1}},
   'lychee': {'availability': {'No': 5, 'Yes': 1}},
   'fig': {'availability': {'No': 2, 'Yes': 2}},
   'blackberry': {'availability': {'No': 2, 'Yes': 5}},
   "india's mangos": {'availability': {'No': 3, 'Yes': 5}},
   'plum': {'availability': {'No': 1, 'Yes': 2}},
   'total_yes': 43,
   'total_no': 3,
   'total': 46,
   'id': [3, 4, 36, 2, 1, 1, 2, 4, 2]}}  
]

如何同时过滤所有大于或等于 5 的 Yes 和 No 值?例如,给定上面的字典。如果字典满足条件,则预期输出应如下所示:

[
{'store': 'walmart',
  'store_id': 0,
  'store_info': {
  'tomatoes': {'availability': {'No': 5, 'Yes': 6}},
  'bottled water': {'availability': {'No': 10, 'Yes': 5}},
  'pineapple': {'availability': {'No': 5, 'Yes': 20}},
  'total_yes': 23,
  'total_no': 23,
  'total': 46,
  'id': [3, 4, 6, 2, 1, 6, 1, 4, 2]}
  }
]

在上面的例子中,'india's mangos': {'availability': {'No': 3, 'Yes': 5}} 应该被过滤或删除。因为,虽然 5 fullfil Yes 门槛,但关键 No,并没有同时达成门槛。或者,'pineapple': {'availability': {'No': 5, 'Yes': 20}} 应保留在字典中,因为 Yes 键的值为 20,大于阈值 5。最后,第二个字典 (costco) 应该被删除,因为它的键都不是至少 5。

到目前为止,我尝试迭代结构,但是,我进行了太多循环,是否有更紧凑的方法来获得预期的输出?:

a_lis = []
for e in list_dict:
    try:
        l = list(e['store_info'].keys())
        for i in l:
            #print(e['store_info'][i]['availability'])
            if e['store_info'][i]['availability']['No']>=5 and e['availability'][i]['availability']['Yes']>= 5:
                a_lis.append(e['store_info'][i]['availability'])
                print(a_lis)
            else:
                pass
    except TypeError:
        pass

【问题讨论】:

  • 你的意思是,“你做的循环太多”?如果它有效,那么嵌套 for 循环就没有错。即使我们确实想出了一个更紧凑的方法来做到这一点,它仍然是一个嵌套的 for 循环。
  • 我猜你想要一个递归解决方案。
  • @JDo 所以基本上,除了更改原始列表而不是创建新列表之外,您想要一种方法来执行上面的操作?
  • @JDo 好的,感谢您澄清您的问题。
  • 我的第二个猜测是修改原始的 dicts 列表(就地,当你迭代它时)会产生比它解决的问题更多的问题

标签: python python-3.x dictionary list-comprehension


【解决方案1】:

这并不难。我建议你创建一个新列表。(并直接修改字典。)

lst = [{'store': 'walmart',
        'store_id': 0,
        'store_info': {'grapes': {'availability': {'No': 1, 'Yes': 1}},
                       'tomatoes': {'availability': {'No': 5, 'Yes': 6}},
                       'oranges': {'availability': {'No': 2, 'Yes': 2}},
                       'bottled water': {'availability': {'No': 10, 'Yes': 5}},
                       'india\'s mangos': {'availability': {'No': 3, 'Yes': 5}},
                       'water melon': {'availability': {'No': 2, 'Yes': 2}},
                       'lemons': {'availability': {'No': 2, 'Yes': 3}},
                       'kiwifruit': {'availability': {'No': 4, 'Yes': 2}},
                       'pineapple': {'availability': {'No': 5, 'Yes': 20}},
                       'total_yes': 23,
                       'total_no': 23,
                       'total': 46,
                       'id': [3, 4, 6, 2, 1, 6, 1, 4, 2]}},
       {'store': 'Costco',
        'store_id': 24,
        'store_info': {
            'papaya': {'availability': {'No': 1, 'Yes': 1}},
                       'lychee': {'availability': {'No': 5, 'Yes': 1}},
                       'fig': {'availability': {'No': 2, 'Yes': 2}},
                       'blackberry': {'availability': {'No': 2, 'Yes': 5}},
                       'india\'s mangos': {'availability': {'No': 3, 'Yes': 5}},
                       'plum': {'availability': {'No': 1, 'Yes': 2}},
                       'total_yes': 43,
                       'total_no': 3,
                       'total': 46,
                       'id': [3, 4, 36, 2, 1, 1, 2, 4, 2]}}
       ]

result_list = []
for sub_dict in lst:
    if sub_dict['store_info']['total_yes'] >= 5 and sub_dict['store_info']['total_no'] >= 5:
        result_list.append(sub_dict)
        key_need_to_be_removed = [k for k, v in sub_dict['store_info'].items() if type(v) is dict and (v['availability']['Yes'] < 5 or v['availability']['No'] < 5)]
        for k in key_need_to_be_removed: # remove the dict under dictionary['store_info']
            del sub_dict['store_info'][k]

print(result_list)

结果:

[{
    'store': 'walmart',
    'store_id': 0,
    'store_info': {
        'tomatoes': {
            'availability': {
                'No': 5,
                'Yes': 6
            }
        },
        'bottled water': {
            'availability': {
                'No': 10,
                'Yes': 5
            }
        },
        'pineapple': {
            'availability': {
                'No': 5,
                'Yes': 20
            }
        },
        'total_yes': 23,
        'total_no': 23,
        'total': 46,
        'id': [3, 4, 6, 2, 1, 6, 1, 4, 2]
    }
}]

【讨论】:

    【解决方案2】:

    这是另一种方法:

    # where data is the input
    filtered = []
    
    for store in data:
        avail_dict = {}
        extra_dict = {}
        for item, value in store['store_info'].items():
            if isinstance(value, dict):
                okay = value['availability'].get('No',0) >= 5 and value['availability'].get('Yes',0) >= 5
                if okay:
                    avail_dict[item] = value
            else:
                extra_dict[item] = value
        if avail_dict:
            avail_dict.update(extra_dict)
            new_store = dict(store)
            new_store['store_info'] = avail_dict
            filtered.append(new_store)
    

    filtered 的结果(输入 data 不变):

    [{'store': 'walmart',
      'store_id': 0,
      'store_info': {'tomatoes': {'availability': {'No': 5, 'Yes': 6}},
       'bottled water': {'availability': {'No': 10, 'Yes': 5}},
       'pineapple': {'availability': {'No': 5, 'Yes': 20}},
       'total_yes': 23,
       'total_no': 23,
       'total': 46,
       'id': [3, 4, 6, 2, 1, 6, 1, 4, 2]}}]
    

    【讨论】:

    • 我收到一个 KeyError:“是”。似乎某些元素没有“是”键。由于不完整,我该如何过滤这些示例?
    • 我添加了 try except,这是否适用于这种情况?
    • 我猜你可以通过使用get 来获取dict 值,如果没有找到则返回0?所以就像value['availability'].get('Yes', 0) &gt;= 5。如果没有是或否意味着没有对该值的响应,这将是有意义的
    • 您能否更新解决方案的完整性?我添加了 try/except 键错误。不过,你的推理更好。
    • 感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2021-10-17
    • 1970-01-01
    • 2021-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-09
    • 1970-01-01
    相关资源
    最近更新 更多