【问题标题】:Filter list of dictionaries by upper/lower limit on values按值的上限/下限过滤字典列表
【发布时间】:2020-11-17 19:34:27
【问题描述】:

我有一个字典列表,我正在尝试为其编写过滤器函数。要过滤的参数将以字典形式给出,其中键是字符串(匹配要过滤的字典列表中的键),值是具有上限和下限的列表。

要过滤的字典列表示例:

test_list = [{'hello':1, 'goodbye':4}, {'hello':7, 'goodbye':6}, {'hello': 4, 'goodbye': 2}]

过滤参数示例:

params = {'hello':[1, 6], 'goodbye':[5, 8]}

我写的函数如下:

def filter_list(target_list, **kwargs):
    filtered_list = target_list
    for k,v in kwargs.items():
        for target in filtered_list:
            if target[k]<v[0] or target[k]>v[1]:
                filtered_list.remove(target)
    return filtered_list

由于某种原因,第二个参数没有被检查,我得到的输出是:

filter_it = filter_list(test_list, **params)
print(filter_it)

>>[{'hello': 4, 'goodbye': 2}]

这是为什么?我认为字典列表中的任何项目都不应该通过标准。但是如果我将参数更改为:

params = {'hello':[1, 8], 'goodbye':[5, 8]}

现在的输出是:

>>[{'hello': 7, 'goodbye': 6}]

要使用的真实数据是一个包含大约 2500 个字典的列表,每个字典有大约 45-50 个键:值对。我需要能够按任意数量的参数进行过滤,因为我并不总是想为每个参数指定上限和下限,因此我不硬编码每个参数的比较。

提前感谢所有/任何帮助!

【问题讨论】:

  • 你的参数是一样的。但是你给出不同的结果。
  • @XuQiushi 是的,抱歉-我刚刚编辑了它!
  • 您正在删除列表项,同时迭代它们..
  • @adirabargil 是的。这个想法是如果项目不满足被评估的条件,则在每次迭代时从列表中删除项目。然后它们不应该在下一次迭代中出现。

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


【解决方案1】:

这是你要找的吗?

result = list(filter(lambda x: all(lower < x[key] < upper 
                                   for key, (lower, upper) in params.items()),
                     test_list))

【讨论】:

  • 这向我抛出了 SyntaxError。有什么遗漏吗?抱歉 - 我还不知道如何使用 lambda 函数,所以我不确定如何自己更正!
  • @ggarfield 是的,我不小心删除了逗号和括号。固定。
  • 行得通!谢谢!你能解释一下 lambda 函数实际上是做什么的吗?这样我以后可以在其他地方实现它:)
【解决方案2】:

这段代码有问题:

for target in filtered_list:
      if target[k]>=v[0] and  target[k]<=v[1]:
            filtered_list.remove(target)

您正在从可防止某些循环的可迭代类型中删除项目...这是一种过滤列表的方法,您最好执行以下操作:

filtered_list = [target for target in filtered_list if target[k]<v[0] or target[k]>v[1]]

【讨论】:

    【解决方案3】:

    你已经得到了答案,所以我只是给你一些额外的解释。

    首先,您的代码在迭代列表时从列表中删除一个项目。所以它会忽略一些项目。例如,当您删除列表的第二项时。然后它将在下一个循环中获取第四项。

    我已经修改了你的原始代码,所以你可以理解它应该是什么。

    首先,您可以使用复制代替移动。

    def filter_list_with_copy(target_list, **kwargs):
        filtered_list = []
        for target in target_list:
            all_satisfied = True
            for k, v in kwargs.items():
                if target[k] < v[0] or target[k] > v[1]:
                    all_satisfied = False
                    break
            if all_satisfied:
                filtered_list.append(target)
        return filtered_list
    

    其次,您可以使用while 代替for。然后你就可以控制你的循环索引了。

    def filter_list_with_while(target_list, **kwargs):
        filtered_list = target_list
        for k, v in kwargs.items():
            filtered_index = 0
            filtered_list_length = len(filtered_list)
            while filtered_index < filtered_list_length:
                target = filtered_list[filtered_index]
                if target[k] < v[0] or target[k] > v[1]:
                    filtered_list.remove(target)
                    filtered_list_length = len(filtered_list)
                else:
                    filtered_index += 1
        return filtered_list
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-21
      • 2019-05-24
      • 1970-01-01
      • 1970-01-01
      • 2020-02-09
      • 1970-01-01
      • 1970-01-01
      • 2017-04-17
      相关资源
      最近更新 更多