Создание понимания списка для dict в списке в списке

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

MyList=[[{'animal':'A','color':'blue'},{'animal':'B','color':'red'}],[{'animal':'C','color':'blue'},{'animal':'D','color':'Y'}]] 

Я хочу извлечь значения для каждого элемента в списке dict / list /, чтобы получить два новых списка:

 Animals=[[A,B],[C,D]] Colors=[[blue,red],[blue,Y]] 

Какие-либо предложения? Не обязательно использовать понимание списка; это лишь моя отправная точка. Благодаря!

 Animals = [[d['animal'] for d in sub] for sub in MyList] Colors = [[d['color'] for d in sub] for sub in MyList] 

Дает желаемый результат:

 [['A', 'B'], ['C', 'D']] [['blue', 'red'], ['blue', 'Y']] # No second 'red'. 

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

В одном задании (с единственным пониманием списка и с помощью map и zip ):

 Colors, Animals = map(list, zip(*[map(list, zip(*[(d['color'], d['animal']) for d in a])) for a in MyList])) - Colors, Animals = map(list, zip(*[map(list, zip(*[(d['color'], d['animal']) for d in a])) for a in MyList])) 

Если вы в порядке с кортежами, вы можете избежать двух вызовов map => list

EDIT :

Давайте рассмотрим это в некоторых деталях, разложив вложенное понимание. Предположим также, что MyList имеет m элементов, для всего n объектов (словарей).

 [[d for d in sub] for sub in MyList] 

Это будет проходить через каждый словарь в подсписках. Для каждого из них мы создаем пару с свойством color в первом элементе и его свойство animal во втором:

 (d['color'], d['animal']) 

Пока это займет время, пропорциональное O(n) – будут обработаны только n элементов.

 print [[(d['color'], d['animal']) for d in sub] for sub in MyList] 

Теперь, для каждого из m подписок в исходном списке, у нас есть один список пар, который нам нужно разархивировать , т. Е. Преобразовать его в два списка одиночных чисел. В Python unzip выполняется с использованием zip функции, передавая переменное количество кортежей в качестве аргументов (арность первого кортежа определяет количество полученных кортежей). Например, пропуская 3 пары, мы получаем два списка по 3 элемента каждый

 >>> zip((1,2), (3,4), (5,6)) #Prints [(1, 3, 5), (2, 4, 6)] 

Чтобы применить это к нашему случаю, нам нужно передать массив пар в zip как переменное число аргументов: это делается с помощью оператора splat , т. Е. *

 [zip(*[(d['color'], d['animal']) for d in sub]) for sub in MyList] 

Эта операция требует прохождения через каждый подсписчик один раз и, в свою очередь, через каждую из пар, которые мы создали на предыдущем шаге. Таким образом, общее время работы O(n + n + m) = O(n) , с приблизительно 2*n + 2*m операций.

Пока у нас есть m подписок, каждый из которых содержит два кортежа (первый соберет все цвета для подсписчика, второй – всех животных). Чтобы получить два списка с m кортежами каждый, мы снова применяем unzip

 zip(*[zip(*[(d['color'], d['animal']) for d in sub]) for sub in MyList] 

Для этого потребуются дополнительные m шагов – поэтому время работы будет оставаться O(n) с приблизительно 2*n + 4*m операциями.

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

Однако кортежи неизменяемы, так что это может быть не так. Если вам нужны списки списков, вам нужно применить функцию list к каждому кортежу: один раз для каждого из сублистов m (всего 2*n элементов) и один раз для каждого из 2 списков первого уровня, то есть животных и Цвета (каждый из которых содержит по m элемента). Для подсчета list требуется время, пропорциональное длине последовательности, к которой оно применяется, для этого дополнительного шага требуются операции 2*n + 2*m , которые все еще O(n) .