Фильтровать список словарей по ключу (а не по значению ключа) в Python

Я хотел бы отфильтровать список (разных) словарей по одному ключу, а не по значению этого ключа.

Это пример:

diclist_example=[{'animal': 'dog', 'legs': 'four'}, 
                {'tvshow': 'Game of Thrones','rating': 'good'},
                {'food': 'banana','color': 'yellow'},
                {'animal': 'sheep', 'legs': 'four'}, 
                {'tvshow': 'Gossip Girl','rating': 'bad'},
                {'food': 'pizza','color': 'red-ish'}]

Проблема с этим, когда я пытаюсь работать с 'animal' значения, например, я получаю KeyError, потому что некоторые диктофоны не содержат 'animal' значение.

Я хотел бы создать новый список словарей, содержащий все словари, основанные на ключе, например, список со всеми животными, список со всеми сериями из списка со всеми продуктами.

5 ответов

Вы можете сделать это с lambda функция, которая фильтрует элементы с пониманием списка. Эта функция вернет список всех идентичных элементов

getAllElementsWithSameKey = lambda key:[d for d in diclist_example if key in d]
getAllElementsWithSameKey('animal')

Вы можете создать список всех своих словарей с

allElements = [getAllElementsWithSameKey(k) for k in ('animal','tvshow','food')]

Ex [Жесткий код]:

l = [dict_elt для dict_elt в diclist_example, если 'animal' в dict_elt]

Создать список словарей автоматически, используя defaultdict,

from collections import defaultdict

diclist_example=[{'animal': 'dog', 'legs': 'four'},
                {'tvshow': 'Game of Thrones','rating': 'good'},
                {'food': 'banana','color': 'yellow'},
                {'animal': 'sheep', 'legs': 'four'},
                {'tvshow': 'Gossip Girl','rating': 'bad'},
                {'food': 'pizza','color': 'red-ish'}]

diclist = defaultdict(list)
for l in diclist_example:
    for k in ('animal','food','tvshow'):
        if k in l:
            diclist[k].append(l)
            break

print(diclist)

результат:

defaultdict(<class 'list'>, {'food': [{'color': 'yellow', 'food': 'banana'}, {'color': 'red-ish', 'food': 'pizza'}], 'tvshow': [{'rating': 'good', 'tvshow': 'Game of Thrones'}, {'rating': 'bad', 'tvshow': 'Gossip Girl'}], 'animal': [{'legs': 'four', 'animal': 'dog'}, {'legs': 'four', 'animal': 'sheep'}]})

Вы также можете попробовать следующий подход:

filter(lambda x: x["animal"] if "animal" in x else None, diclist_example)

Вы должны всегда проверять, существует ли значение, прежде чем что-либо делать с ним, используя оператор if.

if myValue!=None: # or similar, depending on situation
    # do something

Чтобы применить его к вашему примеру:

def zipDict(dicts):
    allKeys = set(k for d in dicts for k in d.keys())
    return {k:[d[k] for d in dicts if (k in d)] for k in allKeys}
                                   ###########  

Вот более подробная версия:

def zipDict(dicts):
    allKeys = set()
    for d in dicts:
        for key in d:
            allKeys.add(key)

    toReturn = {}
    for key in allKeys:
        toReturn[key] = []
        for d in dicts:
            if key in d: # THE GUARDIAN IF STATEMENT THAT PROTECTS YOU
                toReturn[key].append(d[key])

    return toReturn

sidenote: для других пользователей, которые могут наткнуться на этот пост, есть более эффективный метод: вам следует перебирать слова dict, а не allKeys, иначе ваш алгоритм будет O(#keys * #dicts), а не O(N):

def zipDict(dicts):
    R = {}
    for d in dicts:
        for k,v in d.items():
            if not k in R:  # A PROTECTIVE IF STATEMENT
                R[k] = []
            R[k].append(v)
    return R

Вы можете использовать defaultdict, чтобы сделать его немного лучше:

def zipDict(dicts):
    R = defaultdict(list)
    for d in dicts:
        for k,v in d.items():
            R[k].append(v)
    return dict(R)
Другие вопросы по тегам