Python中基于鍵值匹配的多列表字典數據合并與擴展

Python中基于鍵值匹配的多列表字典數據合并與擴展

python中基于鍵值匹配的多列表字典數據合并與擴展教程。本教程詳細講解如何在Python中將多個列表(包含字典數據)進行高效合并與擴展。通過匹配特定鍵的值,我們將演示如何從源列表提取信息(如original_name和original_address)并將其添加到目標列表的相應字典條目中,最終生成一個包含更豐富數據的列表。文章將提供示例代碼,并探討不同實現方式的效率考量。

在數據處理和集成場景中,我們經常需要將分散在不同數據源中的信息合并到一個統一的結構中。特別是在處理列表嵌套字典的數據格式時,根據特定鍵值進行匹配并擴展現有數據是一項常見的操作。本教程將深入探討如何在Python中高效地實現這一目標。

場景描述與問題定義

假設我們有以下三個列表,每個列表都包含一系列字典:

  1. listA: 包含名稱及其原始名稱信息。
    listA = [   {"name": "name sample 1", "original_name" : "original name sample 1"},   {"name": "name sample 2", "original_name" : "original name sample 2"},   # ... 更多數據 ]
  2. listB: 包含地址及其原始地址信息。
    listB = [   {"address": "address sample 1", "original_address" : "original address sample 1"},   {"address": "address sample 2", "original_address" : "original address sample 2"},   # ... 更多數據 ]
  3. dataList: 我們的主數據列表,包含ID、創建時間、名稱和地址。
    dataList = [   {"id": "1", "created_at": "date 1", "name": "name sample 1", "address": "address sample 1"},   {"id": "2", "created_at": "date 2", "name": "name sample 2", "address": "address sample 2"},   # ... 更多數據 ]

我們的目標是創建一個新的列表 finalList,它基于 dataList 的內容,并通過以下規則進行數據擴展:

  • 對于 dataList 中的每個字典,如果其 name 鍵的值與 listA 中某個字典的 name 鍵值匹配,則將 listA 中對應字典的 original_name 值添加到 dataList 的當前字典中。
  • 同樣,如果其 address 鍵的值與 listB 中某個字典的 address 鍵值匹配,則將 listB 中對應字典的 original_address 值添加到 dataList 的當前字典中。

最終 finalList 期望的結構如下:

立即學習Python免費學習筆記(深入)”;

finalList = [   {     "id": "1",     "created_at": "date 1",     "name": "name sample 1",     "original_name" : "original name sample 1",     "address": "address sample 1",     "original_address" : "original address sample 1",   },   # ... ]

解決方案一:基于嵌套循環的直接合并

這種方法直觀且易于理解,適用于數據量不大的場景。其核心思想是遍歷目標列表的每個元素,然后分別遍歷源列表以查找匹配項并更新數據。

實現步驟

  1. 創建副本: 由于我們希望生成一個新的列表而不是修改原始的 dataList,首先使用 copy.deepcopy 創建 dataList 的一個深拷貝作為 finalList。
  2. 合并源列表: 將 listA 和 listB 合并成一個迭代器,這樣可以統一處理兩種類型的匹配。
  3. 嵌套循環: 外層循環遍歷合并后的源列表中的每個條目,內層循環遍歷 finalList 中的每個數據條目。
  4. 條件匹配與更新: 在內層循環中,根據源條目包含的鍵(name 或 address)來判斷匹配類型,然后查找 finalList 中對應的數據條目,如果匹配成功則添加或更新 original_name 或 original_address。

示例代碼

from copy import deepcopy  listA = [   {"name": "name sample 1", "original_name" : "original name sample 1"},   {"name": "name sample 2", "original_name" : "original name sample 2"}, ]  listB = [   {"address": "address sample 1", "original_address" : "original address sample 1"},   {"address": "address sample 2", "original_address" : "original address sample 2"}, ]  dataList = [   {"id": "1", "created_at": "date 1", "name": "name sample 1", "address": "address sample 1"},   {"id": "2", "created_at": "date 2", "name": "name sample 2", "address": "address sample 2"}, ]  # 1. 創建dataList的深拷貝,避免修改原始數據 finalList = deepcopy(dataList)  # 2. 遍歷listA和listB中的所有條目 for entry in listA + listB:     # 3. 根據條目中存在的鍵進行匹配     if "name" in entry:         # 4. 遍歷finalList,查找匹配的name         for data_item in finalList:             if data_item.get('name') == entry['name']:                 data_item['original_name'] = entry['original_name']                 # 找到匹配后可以跳出內層循環,如果name是唯一的                 # break      elif "address" in entry:         # 5. 遍歷finalList,查找匹配的address         for data_item in finalList:             if data_item.get('address') == entry['address']:                 data_item['original_address'] = entry['original_address']                 # 找到匹配后可以跳出內層循環,如果address是唯一的                 # break  print("--- 原始 dataList ---") print(dataList) print("n--- 合并后的 finalList ---") print(finalList)

代碼解析與注意事項

  • from copy import deepcopy: deepcopy 用于創建列表及其內部所有字典的完全獨立副本。如果只使用 finalList = dataList[:] 或 finalList = list(dataList),則只會創建淺拷貝,內部字典仍然是共享的引用,修改 finalList 中的字典會影響 dataList。
  • for entry in listA + listB::這種方式將兩個列表連接起來,使得我們可以統一處理來自不同源的數據。
  • data_item.get(‘name’): 使用 .get() 方法訪問字典鍵是一個好習慣,可以避免在鍵不存在時拋出 KeyError。
  • 效率考量: 這種方法的時間復雜度較高。如果 len(listA) 為 M,len(listB) 為 N,len(dataList) 為 K,那么最壞情況下,總操作數約為 (M + N) * K。對于大型數據集,這可能導致性能瓶頸。

解決方案二:基于哈希映射(字典)的優化合并

為了提高數據量較大時的性能,我們可以利用哈希表(Python中的字典)進行 O(1) 平均時間復雜度的查找。這種方法的核心思想是預先將 listA 和 listB 轉換為查找字典,然后只需遍歷 dataList 一次即可完成數據擴展。

實現步驟

  1. 構建查找字典:
    • 從 listA 構建一個 name_map,其中鍵是 name,值是 original_name。
    • 從 listB 構建一個 address_map,其中鍵是 address,值是 original_address。
  2. 遍歷并更新: 再次創建 dataList 的深拷貝作為 finalList。然后,遍歷 finalList 中的每個字典,使用 name_map 和 address_map 直接查找并添加 original_name 和 original_address。

示例代碼

from copy import deepcopy  listA = [   {"name": "name sample 1", "original_name" : "original name sample 1"},   {"name": "name sample 2", "original_name" : "original name sample 2"}, ]  listB = [   {"address": "address sample 1", "original_address" : "original address sample 1"},   {"address": "address sample 2", "original_address" : "original address sample 2"}, ]  dataList = [   {"id": "1", "created_at": "date 1", "name": "name sample 1", "address": "address sample 1"},   {"id": "2", "created_at": "date 2", "name": "name sample 2", "address": "address sample 2"}, ]  # 1. 構建查找字典 name_map = {item['name']: item['original_name'] for item in listA} address_map = {item['address']: item['original_address'] for item in listB}  # 2. 創建dataList的深拷貝 finalList = deepcopy(dataList)  # 3. 遍歷finalList并使用查找字典進行更新 for data_item in finalList:     # 查找并添加 original_name     name_key = data_item.get('name')     if name_key in name_map:         data_item['original_name'] = name_map[name_key]      # 查找并添加 original_address     address_key = data_item.get('address')     if address_key in address_map:         data_item['original_address'] = address_map[address_key]  print("--- 原始 dataList ---") print(dataList) print("n--- 合并后的 finalList (優化版) ---") print(finalList)

代碼解析與性能分析

  • name_map = {item[‘name’]: item[‘original_name’] for item in listA}: 這是一個字典推導式,高效地將 listA 轉換為一個以 name 為鍵、original_name 為值的字典。address_map 的構建同理。
  • 效率顯著提升:
    • 構建 name_map 的時間復雜度為 O(len(listA))。
    • 構建 address_map 的時間復雜度為 O(len(listB))。
    • 遍歷 finalList 并進行字典查找的時間復雜度為 O(len(dataList)) (平均情況下字典查找為 O(1))。
    • 因此,總時間復雜度為 O(len(listA) + len(listB) + len(dataList)),這比嵌套循環的方法效率高得多,尤其是在 dataList 非常大的情況下。

重要注意事項

  1. 鍵的唯一性: 優化方法要求用于構建查找字典的鍵(如 name 在 listA 中,address 在 listB 中)是唯一的。如果存在重復鍵,字典推導式會覆蓋先前的值,只保留最后一個。如果需要處理重復鍵的復雜邏輯,可能需要更精細的映射結構(例如,值是一個列表)。
  2. 缺失匹配: 如果 dataList 中的某個 name 或 address 在對應的查找字典中不存在,則 original_name 或 original_address 不會被添加到 finalList 中。這是當前邏輯的默認行為。如果需要為缺失項設置默認值(例如 None 或空字符串),可以在 if name_key in name_map: 塊的 else 分支中添加賦值操作。
  3. 數據規模: 對于非常小的數據集(例如,每個列表只有幾十個元素),兩種方法的性能差異可能不明顯。但隨著數據量的增長,基于哈希映射的優化方法將展現出壓倒性的性能優勢。
  4. 內存消耗: 構建查找字典會消耗額外的內存,其大小取決于源列表中唯一鍵的數量。在極端內存受限的場景下,這可能是需要考慮的因素,但通常情況下,其性能收益遠大于內存開銷。

總結與最佳實踐

本教程介紹了兩種在Python中合并和擴展列表字典數據的方法:基于嵌套循環的直接合并和基于哈希映射的優化合并。

  • 嵌套循環法簡單直觀,適用于小規模數據集。
  • 哈希映射法通過預處理源數據為查找字典,顯著提升了大規模數據集的合并效率,是處理此類數據集成任務的首選方法。

在實際開發中,根據您的數據規模、性能要求以及對鍵唯一性的假設,選擇最適合的方案至關重要。通常,推薦優先考慮哈希映射的優化方法,因為它提供了更好的可伸縮性和性能。

? 版權聲明
THE END
喜歡就支持一下吧
點贊13 分享