Фильтровать список словарей по ключам с одним вложенным словарем

Пример:

[{"a":{"x":13, "y":32, "z":33}, "b":5, "c":7, "d":8, "e":9}, {"a":{"x":18, "y":28, "z":38}, "b":57, "c":77, "d":87, "e":97}, {"a":{"x":17, "y":72, "z":73}, "b":58, "c":70, "d":80, "e":90}, ...]

Это всего лишь небольшой набор примеров, но я хотел бы, чтобы список с отфильтрованным списком элементов в каждом словаре, как показано ниже:

Пример вывода:

[{"x":13, "b":5, "e"9}, {"x":18, "b":57, "e"97}, {"x":17, "b":58, "e"90}, ...]

Я могу отфильтровать это до следующего:

[{"a":{"x":13, "y":32, "z":33}, "b":5, "e":9}, {"a":{"x":18, "y":28, "z":38}, "b":57, "e":97}, {"a":{"x":17, "y":72, "z":73}, "b":58, "e":90}, ...]

используя следующий код

for i in range(len(results)):
    desired_keys = ['a', 'b', 'e']
    bigdict = all_results[i]
    filtered = {x: bigdict[x] for x in desired_keys if x in bigdict}

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

Всего 3 ответа


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

>>> [{'x': e['a']['x'], 'b': e['b'], 'e': e['e']} for e in results]
[{'x': 13, 'b': 5, 'e': 9}, {'x': 18, 'b': 57, 'e': 97}, {'x': 17, 'b': 58, 'e': 90}, ...]

Как уже упоминалось, все элементы во вложенных словарях должны быть посещены.

Это рекурсивный подход

vals = [{"a":{"x":13, "y":32, "z":33}, "b":5, "c":7, "d":8, "e":9}, {"a":{"x":18, "y":28, "z":38}, "b":57, "c":77, "d":87, "e":97}, {"a":{"x":17, "y":72, "z":73}, "b":58, "c":70, "d":80, "e":90}]

def get_items(d, keys):
 res = dict()
 for k, v in d.items():
  if isinstance(v, dict):
   res.update(get_items(v, keys))
  elif k in keys:
   res[k] = v
 return res

r = [get_items(d, {'x','b', 'e'}) for d in vals]
print(r)

производит

[{'x': 13, 'b': 5, 'e': 9}, {'x': 18, 'b': 57, 'e': 97}, {'x': 17, 'b': 58, 'e': 90}]

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


Другой возможный рекурсивный подход с функцией генератора:

def get_vals(d, to_find):
   for a, b in d.items():
     if a in to_find:
        yield (a, b)
     yield from [] if not isinstance(b, dict) else get_vals(b, to_find)

data = [{"a":{"x":13, "y":32, "z":33}, "b":5, "c":7, "d":8, "e":9}, {"a":{"x":18, "y":28, "z":38}, "b":57, "c":77, "d":87, "e":97}, {"a":{"x":17, "y":72, "z":73}, "b":58, "c":70, "d":80, "e":90}]
result = [dict(get_vals(i, ['x', 'b', 'e'])) for i in data]

Выход:

[{'x': 13, 'b': 5, 'e': 9}, {'x': 18, 'b': 57, 'e': 97}, {'x': 17, 'b': 58, 'e': 90}]

Есть идеи?

10000