2017-02-14 2 views
3

У меня есть список элементов, хранящихся в формате словаряПоиск минимальных и максимальных элементов в списке элементов словаря

, например.

input_list = [ {'item1': 2, 'item2': 4, 'item3': 3, 'item4': 5, 'item5': 1, 'item6': 2, 'item7': 2, 'item8': 1, 'item9': 2, 'item10': 5, 'item11': 1, 'item12': 2}, 
    {'item1': 4, 'item2': 1, 'item3': 6, 'item4': 2, 'item5': 11, 'item6': 3, 'item7': 4, 'item8': 6, 'item9': 1, 'item10': 5, 'item11': 1, 'item12': 3}] 

У меня есть около 150 элементов в input_list и мне нужно создать два выходных списков (output_list_max и output_list_min), которые должны иметь элементы, как словарь с деталями (т.е. item1, item2..etc) в качестве ключа и значения max/min (writ to entries in input_list) для каждого элемента в качестве значений.

For.eg

output_list_max = [{'item1': 4, 'item2': 4, 'item3': 6, 'item4': 5, 'item5': 11, 'item6': 3, 'item7': 4, 'item8': 6, 'item9': 2, 'item10': 5, 'item11': 1, 'item12': 3}] 

output_list_min = [{'item1': 2, 'item2': 1, 'item3': 3, 'item4': 2, 'item5': 1, 'item6': 2, 'item7': 2, 'item8': 1, 'item9': 1, 'item10': 5, 'item11': 1, 'item12': 2}] 

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

Я надеюсь, что я был в состоянии очистить свои намерения :)

Любая помощь будет оценена спасибо!

+0

Так что вы хотите * поэлементно * минимальный и максимальный? –

+0

Что делать, если ключ отсутствует в одном из словарей? Как '[{'a': 1, 'b': 2}, {'a': 3}]'? –

+0

есть, точно. element-wise max и min – blackbug

ответ

2

Вы можете использовать Counter и использовать & (поэлементное минимум) и | (максимум поэлементное) на них с помощью functools.reduce:

from functools import reduce 
from collections import Counter 

output_list_max = dict(reduce(lambda x,y:x|y,map(Counter,input_list))) 
output_list_min = dict(reduce(lambda x,y:x&y,map(Counter,input_list))) 

В РЕПЛ:

>>> output_list_max 
{'item4': 5, 'item10': 5, 'item3': 6, 'item9': 2, 'item8': 6, 'item2': 4, 'item12': 3, 'item7': 4, 'item6': 3, 'item11': 1, 'item1': 4, 'item5': 11} 
>>> output_list_min 
{'item4': 2, 'item10': 5, 'item3': 3, 'item9': 1, 'item8': 1, 'item2': 1, 'item12': 2, 'item7': 2, 'item6': 2, 'item11': 1, 'item1': 2, 'item5': 1} 

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

Это работает, потому что мы сначала используем map, чтобы преобразовать список словарей в список Counter s. Это делается с помощью map(Counter,input_list).

Следующий reduce(..) используется (на некоторых функциональных языках это называется fold). Если вы подаете reduce(..) список элементов [x1,x2,...,xn] с функцией f, он возвращает f(...f(f(x1,x2),x3)...,xn). В этом случае мы вычисляем таким образом (для первого элемента x1|x2|x3|...|xn). Так как | - это элементный максимум, мы имеем таким образом накопитель (счетчик, который имеет максимальные значения до сих пор), и для каждого нового словаря мы вычисляем новые максимумы. Этот результат возвращается reduce.

+0

. Я готов быть доказанным неправильно, но в быстром тесте 'timeit' это продолжалось примерно в 5 раз медленнее, чем просто повторение всех диктонов. (Может быть, мне нужно добавить больше диктов?) – glibdud

+0

Вы здорово! :) Это прекрасно работает! Благодаря! может объяснить, как это работает, если это возможно. – blackbug

+0

@glibdud: что вы имеете в виду, итерации по словарям? Конечно, вы делаете расчеты, это будет медленнее, чем просто итерация и ничего не делать. –

4

Вы можете использовать zip() с sorted() спарить ваши словарные элементы:

lst = list(zip(*[sorted(d.items()) for d in input_list])) 

dict(max(item) for item in lst) 
# {'item9': 2, 'item4': 5, 'item5': 11, 'item11': 1, 'item2': 4, 'item1': 4, 'item10': 5, 'item6': 3, 'item3': 6, 'item12': 3, 'item7': 4, 'item8': 6} 

dict(min(item) for item in lst) 
# {'item9': 1, 'item4': 2, 'item5': 1, 'item11': 1, 'item2': 1, 'item1': 2, 'item10': 5, 'item6': 2, 'item3': 3, 'item12': 2, 'item7': 2, 'item8': 1} 
+3

+1 Хотя Виллем интересный и умный, это легче понять и, по-видимому, в несколько раз быстрее в быстром тесте 'timeit'. – glibdud

Смежные вопросы