Извлечение данных из вложенных диктов и списков

Скажем, у меня есть дикт, который выглядит так:

dic = {'outer_key_1': {'inner_key_1': [1, 2, 3], 'inner_key_2': [4, 5, 6], 'inner_key_3': [7, 8, 9]}, 'outer_key_2': {'inner_key_1': [11, 12, 13], 'inner_key_2': [14, 15, 16], 'inner_key_3': [17, 18, 19]}} 

Моя цель состоит в том, чтобы извлечь первый элемент из каждого внутреннего dict, заканчивая вложенным списком:

 [[1, 4, 7], [11, 14, 17]] 

Или, альтернативно, диктовать вот так:

 {'outer_key_1': [1, 4, 7], 'outer_key_2': [11, 14, 17]} 

Я попытался получить там с помощью вложенных списков, но лучше всего я мог бы придумать не вложенный список значений результата (более или менее [1, 4, 7, 11, 14, 17] за исключением того, что значения получают перепутаны, что должно быть легко исправить с помощью OrderedDict). Вот довольно уродливое решение, использующее для циклов, но я уверен, что кто-то здесь может придумать что-то лучшее.

 # TODO: find a better way to do this result = [] for inner_dict in dic.values(): result.append([l[0] for l in inner_dict.values()]) print(result) 

который печатает (еще раз значения смешаны, но это не проблема):

 [[14, 17, 11], [4, 7, 1]] 

Какой был бы самый элегантный способ решить это? Я довольно новичок в python, поэтому любые подсказки о том, как подойти к этой проблеме, оцениваются. Я также пробовал экспериментировать с zip , который, я думаю, должен быть довольно приятным способом сделать это, но мне все равно нужно обернуть голову, как использовать это вместе со списком, поэтому … Любые предложения?

Это зависит от того, что вы подразумеваете под элегантностью, но для меня это довольно элегантно, если вы хорошо понимаете функциональное программирование

 [zip(*e)[0] for e in map(dict.values, dic.values())] 

Итак, что он делает

  • dic.values() возвращает список значений в словаре
  • map(dict.values, dic.values()) возвращает вложенные значения второго уровня в словаре
  • наконец, для каждого списка вложенных значений, транспонируйте его с помощью zip и выберите первую строку, которая является первым столбцом в глубоко вложенном dict.

Если вы хотите оптимизировать

  1. Заменить map itertools.imap
  2. Если вы все еще находитесь в Python 2.X, замените dict.values на dict.itervalues

Вот один из способов:

 >>> {outerKey: [innerVal[0] for innerVal in outerVal.itervalues()] for outerKey, outerVal in dic.iteritems()} {'outer_key_1': [4, 7, 1], 'outer_key_2': [14, 17, 11]} 

Это понимание словаря с пониманием списка внутри. Внешнее понимание диктатора повторяется над парами внешних ключей внешнего ключа. Внутреннее понимание списка составляет список первого элемента в каждом внутреннем значении (т. Е. Каждый список во внутреннем dict).

Если вы хотите, чтобы список вместо этого просто превращал понимание dict в понимание списка (удаление ссылки на внешний ключ):

 >>> [[innerVal[0] for innerVal in outerVal.itervalues()] for outerKey, outerVal in dic.iteritems()] [[14, 17, 11], [4, 7, 1]] 

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

Словари в Python по умолчанию не сортируются. Если порядок важен, вы можете сортировать, прежде чем получать значения.

 result = [] for inner_dict in sorted(dic.values()): res = [] for l in sorted(inner_dict.values()): res.append(l[0]) result.append(res) print(result) # Output: [[1, 4, 7], [11, 14, 17]] 

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

Вы можете использовать zip для переноса значений:

 [ (list(zip(*d.values())[0])) for d in dic.values()] [[14, 17, 11], [4, 7, 1]] 

Если вы хотите отсортировать вывод:

 [(list(zip(*sorted(d.values()))[0])) for d in sorted(dic.values())]