Pythonic способ построения фильтра списка

#python

#python

Вопрос:

У меня есть функция для фильтрации списка dict на основе значения определенных ключей, например SELECT * WHERE xxx , запроса в SQL

 list_of_dict = [
{'key1':val, 'key2':val},
{'key1':val, 'key2':val},
...
]

def filter_list(list_of_dict, key1, key2=None):
    if key2:
         filtered_list = [i for i in list_of_dict if i['key1']==key1 and i['key2']==key2]
    else:
         filtered_list = [i for i in list_of_dict if i['key1']==key1]
  

но когда у меня есть больше ключей в качестве аргументов функции if ...else... , это может занять очень много времени.

Есть ли более pythonic способ сделать это?

Ответ №1:

Если у вас большое или переменное количество ключей, вы можете использовать all их для перебора. Вот пример, в котором ключевые значения предоставляются в качестве аргументов ключевого слова:

 def filter_dicts(dicts, **keys):
    return [
        d for d in dicts
        if all(d[k] == v for k, v in keys.items())
    ]
  

Как указывает @juanpa.arrivillaga, dict_items объекты во многих отношениях ведут себя как наборы, поэтому вы можете альтернативно фильтровать словари, которые имеют keys в качестве подмножества:

 def filter_dicts(dicts, **keys):
    return [d for d in dicts if keys.items() <= d.items()]
  

Пример:

 >>> dicts = [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}]
>>> filter_dicts(dicts, x=1)
[{'x': 1, 'y': 2}, {'x': 1, 'y': 3}]
>>> filter_dicts(dicts, x=1, y=2)
[{'x': 1, 'y': 2}]
>>> filter_dicts(dicts, y=3)
[{'x': 1, 'y': 3}]
  

Комментарии:

1. рассмотрим: if keys.items() <= d.items()

2. @juanpa.arrivillaga Я не знал, что вы можете использовать dict_items объект таким образом; если вы опубликуете его в качестве ответа, я проголосую.

3. Эх, суть ответа в использовании **kwargs . Вы можете просто добавить его в качестве альтернативы. Я пытаюсь повысить осведомленность об объектах dict view как объектах, подобных множеству.