2014-02-07 199 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)!