Python 使用多个可能的比较筛选字典

Python 使用多个可能的比较筛选字典,python,json,python-3.x,dictionary,Python,Json,Python 3.x,Dictionary,我正在开发一个网站,其中一部分是一个json字典,其中每个条目都有“coder”、“category”等键,并使用特定的url参数根据类别名称或编码者的名称对其进行过滤。如果用户未进行筛选,则这些URL参数可以是无;如果用户仅筛选特定信息,则这些URL参数可以是部分的 但是,我无法找到一种干净的方法来根据这些值过滤字典。 我希望能够做的是传递“coder”和“category”的值,并创建一个新字典,其中包含与其中指定的内部值匹配的所有内容,如果没有指定参数,则返回整个字典 以下是我现在掌握的一

我正在开发一个网站,其中一部分是一个json字典,其中每个条目都有“coder”、“category”等键,并使用特定的url参数根据类别名称或编码者的名称对其进行过滤。如果用户未进行筛选,则这些URL参数可以是无;如果用户仅筛选特定信息,则这些URL参数可以是部分的

但是,我无法找到一种干净的方法来根据这些值过滤字典。 我希望能够做的是传递“coder”和“category”的值,并创建一个新字典,其中包含与其中指定的内部值匹配的所有内容,如果没有指定参数,则返回整个字典

以下是我现在掌握的一些代码:

def filter_packages(packages, developer=None, category=None):
newpackages = []
for package in packages:
    if developer and category:
        if package["coder"] == developer:
            if package["category"] == category:
                newpackages.append(package)
    elif developer:
        if package["coder"] == developer:
            newpackages.append(package)
    elif category:
        if package["category"] == category:
            newpackages.append(package)
    else:
        newpackages.append(package)

return newpackages
这段代码是不可行的,因为它凌乱、冗长且重复。用户能够应用的过滤器越多,我需要添加的案例就越多。
我想知道如何使用更干净、更具可伸缩性的代码来实现这一点。

您可以将筛选键作为映射:

def filter_packages(packages, filter_keys_map):
  newpackages = []
  for package in packages:
    num_matching_keys = 0
    for key, val in filter_keys_map.items():
      if package[key] == val:
        num_matching_keys += 1
    if num_matching_keys == len(filter_keys_map):
        newpackages.append(package)
  return newpackages   


filter_keys_map = {}
filter_keys_map["coder"] = developer
filter_keys_map["category"] = category
# Make sure to not have a dict entry with null value; in that case remove its key entirely.
filter_packages(packages, filter_keys_map)

这里有一个假设:您传入的关键字参数与字典键具有相同的名称(在您的示例中并非如此,但您可以使用一个映射来调整它,该映射采用关键字参数名称并输出字典键名称-就个人而言,我更愿意调整关键字参数的名称以匹配字典键)

示例:

filter_packages(packages=[{"developer": "foo",
                           "package": "bar"},
                          {"developer": "foo2",
                           "package": "bar"}],
                package="bar",
                developer="foo")

# [{'developer': 'foo', 'package': 'bar'}]

filter_packages(packages=[{"developer": "foo",
                           "package": "bar"},
                          {"developer": "foo2",
                           "package": "bar"}],
                package="bar")

# [{'developer': 'foo', 'package': 'bar'},
#  {'developer': 'foo2', 'package': 'bar'}]
连接词可以任意堆叠,因此是可扩展的

编辑:关于如何使用它:

import requests
packages = requests.get("https://api.oscwii.org/v2/primary/packages").json()

filter_packages(packages,
                coder="Danbo",
                downloads=0)

它应该在不调整当前函数签名的情况下工作(除了将
developer
参数重命名为
coder
之外)。当然,在上面的实现中,您只能支持相等性检查(和逻辑连接)。对于更复杂的筛选条件,您确实可以查看注释中建议的规范设计模式。

是否打算在For循环中返回?还是应该只追加,然后在所有包被迭代后返回?@sim ah不打算这样做,在澄清此问题时忘了删除它。我认为您应该使用规范设计模式,它是专门为处理这种情况而设计的。它的主要优点是,如果您决定添加更多的过滤器,而不是重写所有内容,您只需要扩展类以获得新的过滤器类型。此设计模式指定使用5个可靠的设计原则中的OCP。您可以n在web上查找多个源来实现此功能。这不会产生正确的结果。如果同时提供了“编码器”和“类别”,则两者都必须匹配才能添加包。除了上述注释中所述的内容外,如果未指定“编码器”和“类别”,则它也不会返回任何包。@我认为只有其中一个必须返回匹配要包含的包;这就是为什么我添加了
continue
。修复了它。@GuyTwig修复了它。你能详细说明一下我如何将其用于我的案例吗?为了更清楚,我正在使用的json字典可以在这里找到:添加了一个基于包列表的示例。这似乎有效,谢谢!只有一个示例离题问题:您知道我如何将“”(空字符串)视为无?因为在某些情况下,这是Flask在未指定url参数时返回的结果。您只需在filter\u kwargs.items()中将
return[\u filter\u fun(k,v)更改为filter\u fun(k,v)中的k,v对于k,filter_kwargs.items()中的v如果v]
,则
None
,空字符串也不会产生筛选条件。
import requests
packages = requests.get("https://api.oscwii.org/v2/primary/packages").json()

filter_packages(packages,
                coder="Danbo",
                downloads=0)