如何用其他词典列表过滤词典列表

时间:2019-11-15 13:32:56

标签: python django

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

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

filters = [{'type': 'make', 'value': 'SEAT'}, {'type': 'model', 'value': 'Acura'}]

我的车辆清单如下:

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'},
]

我想获取所有带有make Seatmodel Acura的车辆。因此,我想要的结果是:

[      
  {'make': 'Seat', 'model': 'Acura', 'transmission': 'Manual'}
]

我尝试了如下操作:

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))

但这给了我所有的车辆。

有什么主意吗?

更新

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

filters = [
   {'type': 'make', 'value': 'SEAT'},
   {'type': 'model', 'value': 'Acura'},
   {'type': 'model', 'value': 'LEON'}
]

我想要下一个结果:

[      
  {'make': 'Seat', 'model': 'Acura', 'transmission': 'Manual'},
  {'make': 'Seat', 'model': 'LEON', 'transmission': 'Manual'},
]

我该怎么做?

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

2 个答案:

答案 0 :(得分:3)

鉴于Falsevehicle.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

或者我们可以利用getattr

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

或带有all(..) [python-doc]

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

如果您打算过滤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())

如果您的vehicle不是带有属性的对象,而是字典,则应将getattr(vehicle, k)替换为vehicle[k]

答案 1 :(得分:2)

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'},
]


filters = [
   {'type': 'make', 'value': 'Seat'},
   {'type': 'model', 'value': 'Acura'},
   {'type': 'model', 'value': 'LEON'}
]


filters_ = dict.fromkeys(vehicles[0].keys(), tuple())

for filt in filters:
    filters_[filt['type']] += (filt['value'],) 

[vehicle for vehicle in vehicles 
 if all((vehicle[key] in val or not val) for key, val in filters_.items())]


Out[17]: 
[{'make': 'Seat', 'model': 'Acura', 'transmission': 'Manual'},
 {'make': 'Seat', 'model': 'LEON', 'transmission': 'Manual'}]