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