2015-06-24 3 views
3

У меня есть Dict как этотперебирать список значений словаря

data = { 
    'a': [95, 93, 90], 
    'b': [643, 611, 610] 
} 

Я хочу перебрать Dict и принести ключ и значение из списка значений для каждого элемента, что-то вроде этого

{'a': 95, 'b': 643} 
{'a': 93, 'b': 611} 
{'a': 90, 'b': 610} 

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

import timeit 

data = { 
    'a': [95, 93, 90], 
    'b': [643, 611, 610] 
} 


def calculate(**kwargs): 
    temp_dict = {} 
    index = 0 
    len_values = list(kwargs.values())[0] 

    while index < len(len_values): 
     for k, v in kwargs.items(): 
      temp_dict[k] = v[index] 
     index += 1 
     yield temp_dict 


start_time = timeit.default_timer() 
for k in (calculate(**data)): 
    print(k) 
print(timeit.default_timer() - start_time) 

Как это сделать более эффективно?

+3

Поскольку у вас есть рабочий код, я думаю, вы должны разместить его в разделе Код обзора. – Vaulstein

ответ

13

попробовать что-то вроде этого -

>>> data = { 
...  'a': [95, 93, 90], 
...  'b': [643, 611, 610] 
... } 
>>> lst = list(data.items()) 
>>> lst1 = list(zip(*[i[1] for i in lst])) 
>>> lst1 
[(95, 643), (93, 611), (90, 610)] 
>>> newlist = [] 
>>> for aval, bval in lst1: 
...  newlist.append({lst[0][0]:aval , lst[1][0]:bval}) 
... 
>>> newlist 
[{'a': 95, 'b': 643}, {'a': 93, 'b': 611}, {'a': 90, 'b': 610}] 

При передаче списка, используя * в качестве параметра функции, она будет разбить список на отдельные элементы и передать его на функцию. Пример - если мы пройдем [[1,2],[3,4]] он будет принят в качестве двух различных аргументов - [1,2] и [3,4] - checkt это here (раздел - * в функциональных вызовов)

Пример объяснить это -

>>> lst = [[1,2,3],[4,5,6],[7,8,9]] 
>>> def func(a, b, c): 
...  print(a) 
...  print(b) 
...  print(c) 
... 
>>> func(*lst) 
[1, 2, 3] 
[4, 5, 6] 
[7, 8, 9] 

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


Немного больше масштаба способны модель -

>>> lst = list(data.items()) 
>>> lst 
[('a', [95, 93, 90]), ('b', [643, 611, 610])] 
>>> lst1 = list(zip(*[i[1] for i in lst])) 
>>> lst1 
[(95, 643), (93, 611), (90, 610)] 
>>> newlist = [] 
>>> for x in lst1: 
...  d = {} 
...  for i,y in enumerate(lst): 
...    d[y[0]] = x[i] 
...  newlist.append(d) 
... 
>>> newlist 
[{'a': 95, 'b': 643}, {'a': 93, 'b': 611}, {'a': 90, 'b': 610}] 
+1

Привет, у вас есть ссылка на статью, объясняющую sifnficance '*' in 'list (zip (* data.values ​​())) – shaktimaan

+0

Спасибо большое человеку :) – shaktimaan

+0

Что делать, если dict не известно во время кодирования? – ajkumar25

1

Нечто подобное этому (но заменить на печать с выходом):

keys = [] 
values = [] 
for k, v in data.iteritems(): 
    keys.append(k) 
    values.append(v) 
for vals in zip(*values): 
    print dict(zip(keys, vals)) 

zip(*values) во втором для- петля более или менее transposes список перечней в values. Чуть более компактный способ написания такой же:

keys = list(data) 
for vals in zip(*data.values()): 
    print dict(zip(keys, vals)) 

В обоих случаях результат:

{'a': 95, 'b': 643} 
{'a': 93, 'b': 611} 
{'a': 90, 'b': 610} 
1

Если количество и фактических литералов, используемых в качестве ключей не известны на время кодирования, вот идея :

вы можете дать серию диктоподобных объектов. Каждый экземпляр выведет i-ое значение из списка значений. Вы можете прочитать о emulating python container types.

0

Это один из способов сделать это:

data = { 
    'a': [95, 93, 90], 
    'b': [643, 611, 610] 
} 

x = data.values() 
d1 = {'a':x[0][0], 'b':x[1][0]} 
d2 = {'a':x[0][1], 'b':x[1][1]} 
d3 = {'a':x[0][2], 'b':x[1][2]} 

Выход:

{'a': 95, 'b': 643} 
{'a': 93, 'b': 611} 
{'a': 90, 'b': 610} 
+0

Значок не известен во время кодирования. – ajkumar25

+0

@ ajkumar25 Что значит не знать? –

+0

Ключи от dict будут различаться. Дикт не является постоянным, – ajkumar25

4

Интересный способ сделать это с помощью списка понимания.

>>> data = { 
'a': [95, 93, 90], 
'b': [643, 611, 610] 
} 
>>> [dict(zip(data, x)) for x in zip(*data.values())] 
[{'a': 95, 'b': 643}, {'a': 93, 'b': 611}, {'a': 90, 'b': 610}] 

Или более традиционный (меньше удовольствия) способ

>>> result = [] 
>>> for tuple_ in zip(*data.values()): 
...  d = {} 
...  for key, val in zip(data, tuple_): 
...   d[key] = val 
...  result.append(d) 
>>> print result 
[{'a': 95, 'b': 643}, {'a': 93, 'b': 611}, {'a': 90, 'b': 610}] 

И в комментариях, вот способ сделать это, не полагаясь на «негарантированной» поведения, как же упорядочения данных. keys() и data.values ​​().

Список Постижение

>>> keys, values = zip(*data.items()) 
>>> [dict(zip(keys, tuple_)) for tuple_ in zip(*values)] 
[{'a': 95, 'b': 643}, {'a': 93, 'b': 611}, {'a': 90, 'b': 610}] 

И традиционная для цикла

>>> result = [] 
>>> keys, values = zip(*data.items()) 
>>> for tuple_ in zip(*values): 
...  d = {} 
...  for key, val in zip(keys, tuple_): 
...   d[key] = val 
...  result.append(d) 
>>> print result 
[{'a': 95, 'b': 643}, {'a': 93, 'b': 611}, {'a': 90, 'b': 610}] 
+0

Ваш ответ прекрасен. Это может быть дополнительно расширено, чтобы использовать выражения генератора, что-то вроде 'yield from (dict (zip (kwargs, x)) для x в zip (* kwargs.values ​​())) – ajkumar25

+0

да, трудно найти баланс того, что весело писать и что приемлемо для чтения. – mehtunguh

+1

Словарь не имеет смысла, вы уверены, что ваше решение будет работать все время? –

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