2013-08-17 56 views
16

鑑於列表的字典,例如蟒:通過與列表中的字典迭代值

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

哪個更Python化或以其它方式優選:

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 

還是有其他要考慮的事情?

編輯,如果列表可能有用(例如,標準的字典不保存順序),這可能是適當的,雖然它比較慢。

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

在我的機器上,使用你的代碼,我得到了m1的0.172和m2的0.185。 – 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 

因爲你可以se e,該方法對峯值內存使用率沒有可觀察的影響,但嵌套的for循環在速度上是無法匹敵的(更不用說可讀性)。