2011-03-09 35 views
6

給出兩個字典列表,新的和舊的。字典表示這兩個列表中的相同對象。 我需要找到差異,併產生新的詞典列表,其中只有來自新詞典的對象和來自舊詞典的更新屬性。
例子:匹配詞典集。最好的解決方案。 Python

list_new=[ 
      { 'id':1, 
       'name':'bob', 
       'desc': 'cool gay' 
       }, 

      { 'id':2, 
       'name':'Bill', 
       'desc': 'bad gay' 
       }, 

       { 'id':3, 
       'name':'Vasya', 
       'desc': None 
       }, 
     ] 

    list_old=[ 
      { 'id':1, 
       'name':'boby', 
       'desc': 'cool gay', 
       'some_data' : '12345' 
       }, 
      { 'id':2, 
       'name':'Bill', 
       'desc': 'cool gay', 
       'some_data' : '12345' 

       }, 
       { 'id':3, 
       'name':'vasya', 
       'desc': 'the man', 
       'some_data' : '12345' 
       }, 
       { 'id':4, 
       'name':'Elvis', 
       'desc': 'singer', 
       'some_data' : '12345' 
       }, 
      ] 

所以..在那個例子我想產生新的列表,其中將從list_new唯一的新同性戀者與更新的數據。匹配id。所以Bob會變成Boby,Bill會變成同性戀,Vasya變成 - 男人。終結貓王必須缺席。

給我一個優雅的解決方案。用較少的迭代循環量。

有辦法解決這個問題。哪個不是最好的:

def match_dict(new_list, old_list) 
    ids_new=[] 
    for item in new_list: 
      ids_new.append(item['id']) 
    result=[] 
    for item_old in old_medias: 
     if item_old['id'] in ids_new: 
      for item_new in new_list: 
       if item_new['id']=item_old['id'] 
        item_new['some_data']=item_old['some_data'] 
        result.append(item_new) 
    return result 

我之所以質疑,是因爲裏面有循環循環。如果將有2000個物品的清單,則該過程將需要相同的時間。

+4

只是想知道爲什麼你拼寫'傢伙''同性戀'? – DTing 2011-03-09 21:49:08

+0

請讓貓王逗留:) – 2011-03-09 21:49:42

+1

您是否從某處檢索此列表?你可以使用__id__作爲字典的關鍵字重構字典列表嗎? – 2011-03-09 21:51:44

回答

1

步驟:

  • 創建查找字典list_old通過ID
  • 遍歷list_new類型的字典創建針對每個如果合併字典它存在於舊的

代碼:

def match_dict(new_list, old_list): 
    old = dict((v['id'], v) for v in old_list) 
    return [dict(d, **old[d['id']]) for d in new_list if d['id'] in old] 

編輯:內部函數不正確地命名變量。

+0

我喜歡這個解決方案。美麗。但它已經由科布拉斯給出。謝謝。 – Pol 2011-03-10 15:21:23

+0

只有一個問題是它不保存新對象。這也可以來。但我沒有提到它。 – Pol 2011-03-10 17:50:49

+0

僅供參考,此函數不會返回與原始match_dict()函數相匹配的結果。由於它的名單顛倒了。 – koblas 2011-03-14 16:40:34

1

在old_list,搜索辭典new_list用相同的ID每個字典,然後執行:old_dict.update(new_dict)

消除各new_dict,更新後,從new_list和循環之後的剩餘,未使用的http://stardict.sourceforge.net/Dictionaries.php下載追加。

1

像這樣的東西是你所需要的:

l = [] 
for d in list_old: 
    for e in list_new: 
     if e['id'] == d['id']: 
      l.append(dict(e, **d)) 
print l 

關於如何合併字典讀here

0

如果您的頂級數據結構是字典而不是列表,那麼您會好得多。那麼這將是:

dict_new.update(dict_old) 

但是,你確實有,試試這個:

result_list = [] 
for item in list_new: 
    found_item = [d for d in list_old if d["id"] == item["id"]] 
    if found_item: 
     result_list.append(dict(item, **found_item[0])) 

這實際上仍然在循環中循環(內循環是在列表中的「隱藏」理解),所以它仍然是O(N ** 2)。在大型數據集上,將其轉換爲字典無疑會更快,然後將其更改爲列表。

1

你可以做這樣的事情:

def match_dict(new_list, old_list): 
    new_dict = dict((obj['id'], obj) for obj in new_list) 
    old_dict = dict((obj['id'], obj) for obj in old_list) 
    for k in new_dict.iterkeys(): 
     if k in old_dict: 
      new_dict[k].update(old_dict[k]) 
     else: 
      del new_dict[k] 
    return new_dict.values() 

如果你正在做的這個時候,我會建議將數據存儲爲與ID爲重點,而非列表字典,這樣你就不必每次都進行轉換。

編輯:以下示例顯示如何將數據存儲在字典中。

list_new = [{'desc': 'cool guy', 'id': 1, 'name': 'bob'}, {'desc': 'bad guy', 'id': 2, 'name': 'Bill'}, {'desc': None, 'id': 3, 'name': 'Vasya'}] 
# create a dictionary with the value of 'id' as the key 
dict_new = dict((obj['id'], obj) for obj in list_new) 
# now you can access entries by their id instead of having to loop through the list 
print dict_new[2] 
# {'id': 2, 'name': 'Bill', 'desc': 'bad guy'} 
+0

你是什麼意思字典作爲關鍵?我可以有一些文檔鏈接嗎?或看到一些例子? – Pol 2011-03-10 14:59:59

3

不能完全得到它的一條線,但這裏有一個簡單的版本:

def match_new(new_list, old_list) : 
    ids = dict((item['id'], item) for item in new_list) 
    return [ids[item['id']] for item in old_list if item['id'] in ids] 
2

不知道你的數據的制約,我會假設id是每個列表中獨一無二的,你的列表只包含可變的類型(string,int,...),它們是可散列的。

# first index each list by id 
new = {item['id']: item for item in list_new} 
old = {item['id']: item for item in list_old} 

# now you can see which ids appeared in the new list 
created = set(new.keys())-set(old.keys()) 
# or which ids were deleted 
deleted = set(old.keys())-set(new.keys()) 
# or which ids exists in the 2 lists 
intersect = set(new.keys()).intersection(set(old.keys())) 

# using the same 'conversion to set' trick, 
# you can see what is different for each item 
diff = {id: dict(set(new[id].items())-set(old[id].items())) for id in intersect} 

# using your example data set, diff now contains the differences for items which exists in the two lists: 
# {1: {'name': 'bob'}, 2: {'desc': 'bad gay'}, 3: {'name': 'Vasya', 'desc': None}} 

# you can now add the new ids to this diff 
diff.update({id: new[id] for id in created}) 
# and get your data back into the original format: 
list_diff = [dict(data, **{'id': id}) for id,data in diff.items()] 

這是使用python 3語法,但應該很容易地移植到Python 2

編輯:

new = dict((item['id'],item) for item in list_new) 
old = dict((item['id'],item) for item in list_old) 

created = set(new.keys())-set(old.keys()) 
deleted = set(old.keys())-set(new.keys()) 
intersect = set(new.keys()).intersection(set(old.keys())) 

diff = dict((id,dict(set(new[id].items())-set(old[id].items()))) for id in intersect) 

diff.update(dict(id,new[id]) for id in created)) 
list_diff = [dict(data, **{'id': id}) for id,data in diff.items()] 

這裏是相同的代碼爲Python 2.5編寫(注意如何在沒有詞典理解的情況下代碼不易讀)

+0

是的id是唯一的。 Python 2.6 – Pol 2011-03-10 05:37:34

+0

這很不錯。有5個循環。但是x * 5小於x * x。如果x有時可以等於300.謝謝。 – Pol 2011-03-10 14:27:16

0

你可能喜歡這個。請看看,謝謝。

def match_dict(new_list, old_list): 
    id_new = [item_new.get("id") for item_new in list_new] 
    id_old = [item_old.get("id") for item_old in list_old] 

    for idx_old in id_old: 
     if idx_old in id_new: 
      list_new[id_new.index(idx_old)].update(list_old[id_old.index(idx_old)]) 

    return list_new 

from pprint import pprint 
pprint(match_dict(list_new, list_old)) 

輸出:

[{'desc': 'cool gay', 'id': 1, 'name': 'boby', 'some_data': '12345'}, 
{'desc': 'cool gay', 'id': 2, 'name': 'Bill', 'some_data': '12345'}, 
{'desc': 'the man', 'id': 3, 'name': 'vasya', 'some_data': '12345'}] 
0
[od for od in list_old if od['id'] in {nd['id'] for nd in list_new}] 
+0

這個不會更新新字典附帶的其他數據。 – Pol 2011-03-10 07:33:34