2014-02-07 88 views
1

這是我想要實現的:Python:比較兩個字典列表

我有兩個字典列表。所有字典具有以下結構:

dictinary = {'name':'MyName', 'state':'MyState'} 

我想經過兩個列表中的所有元素和條目的狀態具有相同名稱的比較。下面是我所能想象的最好辦法:

for d in list1: 
    name = d['name'] 
    for d2 in list2: 
     if d2['name'] == name: 
      if d1['state'] != d2['state']: 
       # Do something 

雖然我認爲這種方法是有效的,我不知道是否有執行此操作的更有效的和/或優雅的方式。感謝您的想法!

+0

@tobias_k因爲在我的程序中,我使用字典來生成json對象。由於字典所代表的對象的數量可能會有所不同,我想我需要一個列表。 – fedorSmirnov

+0

(對不起,點擊編輯而不是添加評論)。托比亞斯問道,爲什麼我使用兩個字典列表而不是兩個字典。 – fedorSmirnov

回答

2

有從itertools看看product

import itertools 

xs = range(1,10) 
ys = range(11,20) 

zs = itertools.product(xs,ys) 

list(zs) 

[(1,11) (1,12),(1,13),(1,14),(1,15),(1,16),(1,17),(1,18),(1,19),(2) ,(2,12),(2,13),(2,14),(2,15),(2,16),(2,17),(2,18),(2,19 ),(3,11),(3,12),(3,13),(3,14),(3,15),(3,16),(3,17),(3,18), (4,19),(4,11),(4,12),(4,13),(4,14),(4,15),(4,16),(4,17),(4 ,18),(4 (5,11),(5,12),(5,13),(5,14),(5,15),(5,16),(5,17),(5,18 ),(5,19),(6,11),(6,12),(6,13),(6,14),(6,15),(6,16),(6,17), (6,18),(6,19),(7,11),(7,12),(7,13),(7,14),(7,15),(7,16),(7 (8,11),(8,12),(8,13),(8,14),(8,15),(8,16), ),(8,17),(8,18),(8,19),(9,11),(9,12),(9,13),(9,14),(9,15), (9,16),(9,17),(9,18),(9,19)]

幾個其他的事情 -

  1. 當你只表示了兩兩件事,它是共同使用一個元組(即使是一個命名元組) 所以有一個思考,爲什麼他們是先從字典 - 你可能有一個很好的理由:)

[('name','state'),('name','state'),('name','state')...]

另一種方法,將是直接比較元件,例如,你可以檢查組A(1 http://stardict.sourceforge.net/Dictionaries.php下載的列表)和組B(2 http://stardict.sourceforge.net/Dictionaries.php下載的列表)的交點

>>> listA = [('fred','A'), ('bob','B'), ('mary', 'D'), ('eve', 'E')] 
>>> listB = [('fred','X'), ('clive', 'C'), ('mary', 'D'), ('ben','B')] 
# your listA and listB could be sets to begin with 
>>> set.intersection(set(listA),set(listB)) 
set([('mary', 'D')]) 

然而,這種方法不允許重複...

1

我能想到的最優雅的方式是列表理解。

[[do_something() for d1 in list1 if d1["name"] == d2["name"] and d1["state"] != d2["state"]] for d2 in list2] 

但是這是相同的代碼。

您也可以讓你的示例代碼更優雅一點減少了一點:

for d in list1: 
    for d2 in list2: 
     if d2['name'] == d['name'] and d['state'] != d2['state']: 
      # Do something 
+0

確保您使用'=='來測試是否相等,而不是'='。 – senshin

+0

謝謝,修正。 – icedtrees

1

其他答案是功能性的(他們提供了正確的答案),但是對於大型列表來說效果不好,因爲他們使用嵌套迭代 - 對於長度爲N的列表,該他們使用的步數增長如N^2。如果名單很小,這不是一個問題;但是如果列表很大,迭代的次數就會爆炸。

另一種方法,保持時間複雜度線性有N是這樣的(是非常詳細):

## 
## sample data 
data = list() 
data.append([ 
    dict(name='a', state='0'), 
    dict(name='b', state='1'), 
    dict(name='c', state='3'), 
    dict(name='d', state='5'), 
    dict(name='e', state='7'), 
    dict(name='f', state='10'), 
    dict(name='g', state='11'), 
    dict(name='h', state='13'), 
    dict(name='i', state='14'), 
    dict(name='l', state='19'), 
    ]) 
data.append([ 
    dict(name='a', state='0'), 
    dict(name='b', state='1'), 
    dict(name='c', state='4'), 
    dict(name='d', state='6'), 
    dict(name='e', state='8'), 
    dict(name='f', state='10'), 
    dict(name='g', state='12'), 
    dict(name='j', state='16'), 
    dict(name='k', state='17'), 
    dict(name='m', state='20'), 
    ]) 

## 
## coalesce lists to a single flat dict for searching 
dCombined = {} 
for d in data: 
    dCombined = { i['name'] : i['state'] for i in d } 

## 
## to record mismatches 
names = [] 

## 
## iterate over lists -- individually/not nested 
for d in data: 
    for i in d: 
     if i['name'] in dCombined and i['state'] != dCombined[i['name']]: 
      names.append(i['name']) 

## 
## see result 
print names 

注意事項:

的OP沒有說,如果有可能中的重複名稱列表;那會稍微改變這種方法。

根據「做某事」的細節,您可能會記錄除名稱之外的其他東西 - 可以存儲單個字典對象的引用或副本,或任何「執行某些」操作所需的內容。

這種方法的權衡是需要比以前的答案更多的內存;然而,內存需求只與實際不匹配的數量成正比,並且是O(N)。

注:

這種方法也適用,當你有2點以上的列表進行比較 - 例如如果有5個列表,我的選擇在時間和記憶上仍然是O(N),而以前的答案在時間上是O(N^5)!