2013-08-17 20 views
16

Biorąc słownik list, takich jakpython: iteracja słownika z listy wartości

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

Która jest bardziej pythonic lub inaczej preferowane:

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

lub

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

czy jest jeszcze coś do rozważenia?

EDYCJA, na wypadek gdyby lista mogła być przydatna (np. Standardowe dicty nie zachowują porządku), może to być odpowiednie, chociaż jest znacznie wolniejsze.

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

Wolę drugi, ale są one równie jasne. – bbayles

+0

dlaczego niewiele więcej pythonic ze zrozumieniem listy? – woofmeow

+0

@woofmeow proszę wyjaśnić – foosion

Odpowiedz

11

Oto test prędkości, dlaczego nie:

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 przykład wyjście:

  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() jest nieco szybszy i ma "iter" w nazwie . Czego można chcieć więcej? :-) – foosion

+0

Na moim komputerze uzyskuję 0.172 dla m1 i 0.185 dla m2 używając twojego kodu. – foosion

+0

Dziwne - próbowałem jeszcze kilka razy, a m1 konsekwentnie zajmuje około 15% więcej czasu na mojej maszynie. Python 2.7, Intel i5. – Brionius

1

Oto lista podejście ze zrozumieniem. Zagnieżdżone ...

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

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

Dla czegoś takiego, d.items() wydaje się być lepszy, przynajmniej dla mnie, szczególnie jeśli chcesz coś zrobić za pomocą obu kluczy i wartości. – foosion

+0

Cóż, prawda ... Naprawdę nie wiem, jaki jest twój przypadek użycia. Poprosiłeś @woofmeow o wyjaśnienia w zakresie rozumienia list. – kelorek

+0

Bez obaw. Przypuszczam, że tak naprawdę pytałem, w jaki sposób zrozumienie list było odpowiedzią na pytanie, które (zgodnie z edycją) chce zrobić z kluczem i wartościami. – foosion

2

Moje wyniki z kodem 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

Rozważałem kilka metod:

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 

użyłem ipython i memory_profiler do testowania wydajności:

>>> %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 

Jak możesz se e, metoda nie miała zauważalnego wpływu na wykorzystanie pamięci szczytowej, ale zagnieżdżone pętle for były nie do pokonania dla szybkości (nie wspominając o czytelności).

Powiązane problemy