如何使用另一个字典列表过滤字典列表

Bok*_*oky 1 python django

我想用 Python 和 Django 中的另一个字典列表来过滤字典列表。

我有一个过滤器列表,如下所示:

filters = [{'type': 'make', 'value': 'SEAT'}, {'type': 'model', 'value': 'Acura'}]
Run Code Online (Sandbox Code Playgroud)

我有一个车辆列表如下:

vehicles = [
  {'make': 'Audi', 'model': 'A3', 'transmission': 'Manual'},
  {'make': 'Audi', 'model': 'A1', 'transmission': 'Automatic'},
  {'make': 'Seat', 'model': 'Acura', 'transmission': 'Manual'},
  {'make': 'Seat', 'model': 'LEON', 'transmission': 'Manual'},
  {'make': 'Skoda', 'model': 'Octavia', 'transmission': 'Manual'},
]
Run Code Online (Sandbox Code Playgroud)

我想获得所有带有make Seat和 的车辆model Acura。因此我想要的结果是:

[      
  {'make': 'Seat', 'model': 'Acura', 'transmission': 'Manual'}
]
Run Code Online (Sandbox Code Playgroud)

我尝试了如下方法:

def filter_item(vehicle, filters):
    for fil in filters:
        key = fil['type']
        value = fil['value']
        if key == 'make':
            if vehicle.make == value:
                continue
        elif key == 'model':
            if vehicle.model == value:
                continue
        else:
            return False

    return True

vehicles = list(filter(lambda vehicle: filter_item(vehicle, filters), vehicles))
Run Code Online (Sandbox Code Playgroud)

但这给了我所有车辆。

任何想法?

更新

因此,如果我有如下过滤器:

filters = [
   {'type': 'make', 'value': 'SEAT'},
   {'type': 'model', 'value': 'Acura'},
   {'type': 'model', 'value': 'LEON'}
]
Run Code Online (Sandbox Code Playgroud)

我想要下一个结果:

[      
  {'make': 'Seat', 'model': 'Acura', 'transmission': 'Manual'},
  {'make': 'Seat', 'model': 'LEON', 'transmission': 'Manual'},
]
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

我需要更改列表的结构filters吗?

Wil*_*sem 5

False由于与以下内容vehicle.make不同,您的过滤不会返回value

您可以将过滤器重写为:

def filter_item(vehicle, filters):
    for fil in filters:
        key = fil['type']
        value = fil['value']
        if key == 'make':
            if vehicle.make != value:
                return False
        elif key == 'model':
            if vehicle.model != value:
                return False
        else:
            return False
    return True
Run Code Online (Sandbox Code Playgroud)

或者我们可以利用getattr

def filter_item(vehicle, filters):
    for fil in filters:
        if fil['value'] != getattr(vehicle, fil['type']):
            return False
    return True
Run Code Online (Sandbox Code Playgroud)

或使用all(..)[python-doc]

def filter_item(vehicle, filters):
    return all(fil['value'] == getattr(vehicle, fil['type']) for fil in filters)
Run Code Online (Sandbox Code Playgroud)

如果您的目标是过滤 Django 记录,那么我强烈建议在数据库上尽可能多地进行过滤,因为数据库已针对此任务进行了优化。

编辑:您可以对同一字段的析取进行合取。例如通过预处理过滤器:

from collections import defaultdict

filter_dict = defaultdict(set)
for fil in filters:
    filter_dict[fil['type']].add(fil['value'])

def filter_item(vehicle):
    return all(getattr(vehicle, k) in v for k, v in filter_dict.items())
Run Code Online (Sandbox Code Playgroud)

如果你的vehicle不是一个带有属性的对象,而是一个字典,你应该替换getattr(vehicle, k)vehicle[k].