2013-08-17 4 views
16

Учитывая словарь списков, такие какпитона: перебор словаря со списком значения

d = {'1':[11,12], '2':[21,21]} 

Что более вещий или иначе предпочтительнее:

for k in d: 
    for x in d[k]: 
     # whatever with k, x 

или

for k, dk in d.iteritems(): 
    for x in dk: 
     # whatever with k, x 

или есть что-то еще, чтобы рассмотреть?

EDIT, если список может быть полезен (например, стандартные дикты не сохраняют порядок), это может быть уместно, хотя оно намного медленнее.

d2 = d.items() 
for k in d2: 
     for x in d2[1]: 
      # whatever with k, x 
+0

Я предпочитаю второй, но они примерно одинаково понятны. – bbayles

+0

Почему не намного больше pythonic со списком? – woofmeow

+0

@woofmeow, пожалуйста, уточните – foosion

ответ

11

Вот тест скорости, почему бы не:

import random 
numEntries = 1000000 
d = dict(zip(range(numEntries), [random.sample(range(0, 100), 2) for x in range(numEntries)])) 

def m1(d): 
    for k in d: 
     for x in d[k]: 
      pass 

def m2(d): 
    for k, dk in d.iteritems(): 
     for x in dk: 
      pass 

import cProfile 

cProfile.run('m1(d)') 

print 

cProfile.run('m2(d)') 

# Ran 3 trials: 
# m1: 0.205, 0.194, 0.193: average 0.197 s 
# m2: 0.176, 0.166, 0.173: average 0.172 s 

# Method 1 takes 15% more time than method 2 

Cprofile пример вывода:

  3 function calls in 0.194 seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.000 0.000 0.194 0.194 <string>:1(<module>) 
     1 0.194 0.194 0.194 0.194 stackoverflow.py:7(m1) 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 



     4 function calls in 0.179 seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.000 0.000 0.179 0.179 <string>:1(<module>) 
     1 0.179 0.179 0.179 0.179 stackoverflow.py:12(m2) 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 
     1 0.000 0.000 0.000 0.000 {method 'iteritems' of 'dict' objects} 
+2

iteritems() немного быстрее и имеет 'iter' в своем названии , Что еще можно спросить? :-) – foosion

+0

На моей машине я получаю 0.172 для m1 и 0.185 для m2, используя ваш код. – foosion

+0

Как странно - я попробовал еще несколько раз, и m1 последовательно занимает около 15% больше времени на моей машине. Python 2.7, Intel i5. – Brionius

1

Вот список понимание подход. Вложенные ...

r = [[i for i in d[x]] for x in d.keys()] 
print r 

[[11, 12], [21, 21]] 
+0

Для чего-то вроде этого d.items() кажется лучше, по крайней мере для меня, особенно если вы хотите что-то сделать с помощью обоих ключей и значений. – foosion

+0

Ну, правильно .. Я действительно не знаю, что такое ваш случай использования. Вы попросили @woofmeow для разъяснения по спискам. – kelorek

+0

Не беспокойтесь. Я полагаю, что я действительно спрашивал, как понимание списков реагирует на вопрос, который (как отредактирован) хочет что-то сделать с ключом и значениями. – foosion

2

Мои результаты Brionius кода:

  3 function calls in 0.173 seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.000 0.000 0.173 0.173 <string>:1(<module>) 
     1 0.173 0.173 0.173 0.173 speed.py:5(m1) 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Prof 
iler' objects} 


     4 function calls in 0.185 seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.000 0.000 0.185 0.185 <string>:1(<module>) 
     1 0.185 0.185 0.185 0.185 speed.py:10(m2) 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Prof 
iler' objects} 
     1 0.000 0.000 0.000 0.000 {method 'iteritems' of 'dict' obje 
cts} 
2

Я считал пару методов:

import itertools 

COLORED_THINGS = {'blue': ['sky', 'jeans', 'powerline insert mode'], 
        'yellow': ['sun', 'banana', 'phone book/monitor stand'], 
        'red': ['blood', 'tomato', 'test failure']} 

def forloops(): 
    """ Nested for loops. """ 
    for color, things in COLORED_THINGS.items(): 
     for thing in things: 
      pass 

def iterator(): 
    """ Use itertools and list comprehension to construct iterator. """ 
    for color, thing in (
     itertools.chain.from_iterable(
      [itertools.product((k,), v) for k, v in COLORED_THINGS.items()])): 
     pass 

def iterator_gen(): 
    """ Use itertools and generator to construct iterator. """ 
    for color, thing in (
     itertools.chain.from_iterable(
      (itertools.product((k,), v) for k, v in COLORED_THINGS.items()))): 
     pass 

я использовал IPython и memory_profiler для тестирования производительности:

>>> %timeit forloops() 
1000000 loops, best of 3: 1.31 µs per loop 

>>> %timeit iterator() 
100000 loops, best of 3: 3.58 µs per loop 

>>> %timeit iterator_gen() 
100000 loops, best of 3: 3.91 µs per loop 

>>> %memit -r 1000 forloops() 
peak memory: 35.79 MiB, increment: 0.02 MiB 

>>> %memit -r 1000 iterator() 
peak memory: 35.79 MiB, increment: 0.00 MiB 

>>> %memit -r 1000 iterator_gen() 
peak memory: 35.79 MiB, increment: 0.00 MiB 

Как вы можете e, метод не имел заметного влияния на использование пиковой памяти, но вложенные петли for были непревзойденными для скорости (не говоря уже о читаемости).

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