2013-08-17 45 views
16

Với một cuốn từ điển các danh sách, chẳng hạn nhưpython: lặp thông qua một cuốn từ điển với danh sách các giá trị

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

Đó là pythonic hơn hoặc bằng cách khác thích hợp hơn:

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

hoặc

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

hoặc có cái gì khác để xem xét?

CHỈNH SỬA, trong trường hợp danh sách có thể hữu ích (ví dụ: các dicts tiêu chuẩn không giữ được thứ tự), điều này có thể phù hợp, mặc dù nó chậm hơn nhiều.

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

Tôi thích thứ hai, nhưng chúng đều rõ ràng. – bbayles

+0

tại sao không nhiều hơn nữa pythonic với danh sách comprehensions? – woofmeow

+0

@woofmeow xin vui lòng làm rõ – foosion

Trả lời

11

Dưới đây là một thử nghiệm tốc độ, tại sao không:

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 dụ đầu ra:

  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() là một chút nhanh hơn và có 'iter' trong tên của nó . Còn ai có thể hỏi? :-) – foosion

+0

Trên máy tính của tôi, tôi nhận được 0.172 cho m1 và 0.185 cho m2 sử dụng mã của bạn. – foosion

+0

Làm thế nào lạ - Tôi đã thử nó một vài lần, và m1 luôn mất khoảng 15% thời gian hơn trên máy tính của tôi. Python 2.7, Intel i5. – Brionius

1

Dưới đây là cách tiếp cận danh sách hiểu. Lồng ...

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

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

Đối với một cái gì đó như thế, d.items() có vẻ tốt hơn, ít nhất là với tôi, đặc biệt là nếu bạn muốn làm điều gì đó với cả khóa và giá trị. – foosion

+0

Vâng, đúng .. Tôi không thực sự biết trường hợp sử dụng của bạn là gì. Bạn đã hỏi @woofmeow để làm rõ về danh sách hiểu. – kelorek

+0

Không phải lo lắng. Tôi cho rằng những gì tôi đã thực sự hỏi là làm thế nào một danh sách hiểu được đáp ứng với một câu hỏi mà (như chỉnh sửa) muốn làm điều gì đó với chìa khóa và các giá trị. – foosion

2

kết quả của tôi từ mã 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

tôi coi là một vài phương pháp:

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 

tôi đã sử dụng ipython và memory_profiler để kiểm tra hiệu suất:

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

Như bạn có thể e, phương pháp không có tác động quan sát được khi sử dụng bộ nhớ đỉnh, nhưng các vòng lặp for lồng nhau là không thể cạnh tranh cho tốc độ (không kể đến khả năng đọc).

Các vấn đề liên quan