HOWTO · Python

在 Python 中的查找表

本教程演示了如何在 Python 中使用查找表,重點介紹字典、列表、NumPy 陣列和 Pandas DataFrame 等方法。學習實現高效的數據檢索技術,以優化您的編程技能並提高應用性能。探索實用的代碼示例和詳細說明,以掌握 Python 中的查找表。

本頁內容

查詢表會儲存值,讓程式能依鍵或位置取回資料。當程式需要反覆查詢相同的對應關係時,查詢表就很實用,例如將產品代碼對應到價格。預先計算結果可以避免重複執行計算,但查詢表會占用記憶體,而且來源資料變動時也必須更新。

請根據鍵的形式和要執行的操作選擇資料結構:字典接受任意可雜湊的鍵;列表和陣列使用整數位置;DataFrame 則支援具名欄位和表格操作。以下範例會說明各種結構如何處理實際查詢。

為資料選擇合適的查詢表結構

先想想要用什麼來識別一個值。名稱、代碼或其他非密集整數位置的鍵,適合用字典。若位置是從零開始、連續排列的整數,而且值可以放在 Python 序列中,則可使用列表。資料為數值,且需要向量化計算、切片或其他陣列操作時,可使用 NumPy 陣列。若每筆記錄有多個具名欄位,或需要篩選及其他表格操作,則可使用 Pandas DataFrame。NumPy 和 Pandas 是第三方套件;使用範例前,請先在專案環境中安裝。

使用字典依鍵查詢

字典會將每個相異且可雜湊的鍵對應到一個值。它適合用於非連續的鍵,也能透過 get 明確指定備用值。鍵不存在時,get 會傳回你提供的預設值;使用方括號存取則會在鍵不存在時引發 KeyError。

執行以下範例:

本節中的程式碼以及顯示的標籤或輸出仍為英文。

prices = {"tea": 2.5, "coffee": 3.0, "cocoa": 2.75}
print(prices["tea"])
print(prices.get("juice", "not listed"))
2.5
not listed

字典查詢的平均時間複雜度為 O(1),但這不代表所有工作負載都能獲得保證。鍵必須可雜湊;若將值指定給已存在的鍵,原有值會被取代。來源記錄變動時,也要一併更新字典,避免查詢結果過時。

使用列表處理密集整數索引

當有效索引從零開始且密集連續時,列表是簡單的查詢表:索引 i 指向第 (i + 1) 個項目。對於客戶編號等稀疏識別碼,列表就不合適,因為索引間的空缺必須以未使用的項目填滿,或另外建立映射。列表索引的時間複雜度為 O(1);其中的值仍是一般 Python 物件。

本節中的程式碼以及顯示的標籤或輸出仍為英文。

labels = ["bronze", "silver", "gold"]

def label_for(index):
    if 0 <= index < len(labels):
        return labels[index]
    return "index out of range"

print(label_for(2))
print(label_for(5))
gold
index out of range

明確檢查範圍可以處理小於零,以及大於或等於列表長度的索引。Python 列表也允許負索引從尾端往前計數;如果查詢表的鍵只包含非負位置,請先驗證索引。

使用 NumPy 陣列處理數值資料

若查詢表包含數值,且還需要向量化計算、切片或其他陣列操作,NumPy 陣列會很實用。NumPy 必須另外安裝,並非 Python 標準函式庫的一部分。純量查詢仍只是依索引取值,因此陣列不會自動成為比字典更快的替代方案。

本節中的程式碼以及顯示的標籤或輸出仍為英文。

import numpy as np

rates = np.array([1.0, 1.5, 2.0, 2.5])
index = 2
if 0 <= index < len(rates):
    print(rates[index])
else:
    print("index out of range")
print((rates * 2).tolist())
2.0
[2.0, 3.0, 4.0, 5.0]

索引來自外部輸入時,範圍檢查尤其實用。NumPy 陣列通常使用單一元素型別,這有利於數值運算;請依照要儲存的資料選擇合適的元素型別和形狀。

使用 Pandas DataFrame 處理表格資料

DataFrame 適合包含具名欄位的記錄,尤其是查詢屬於較大型篩選或分析工作的一部分時。Pandas 必須另外安裝。依欄位篩選會比對各列;若只選取符合條件的列,結果會是 DataFrame。在下方的運算式中,透過 .loc 選取單一 price 欄位會傳回 Series;篩選可能需要掃描各列。若要反覆依鍵查詢,可考慮設定有意義的索引,再使用 .loc。

本節中的程式碼以及顯示的標籤或輸出仍為英文。

import pandas as pd

items = pd.DataFrame({
    "code": ["A", "B", "C"],
    "price": [1.25, 2.50, 3.75],
})
match = items.loc[items["code"] == "B", "price"]
if not match.empty:
    print(match.iloc[0])
else:
    print("not found")
2.5

這種寫法能在找不到相符代碼時避免索引空結果。若代碼唯一且會反覆查詢,items.set_index("code").loc["B", "price"] 可用來依標籤查找;存取前請確認代碼存在,並決定如何處理重複標籤。

處理缺少的鍵和無效索引

請依呼叫端的需求選擇缺值處理方式。dict.get(key, default) 會傳回備用值;key in mapping 則能區分鍵不存在,以及鍵存在但其值剛好等於備用值的情況。若周邊邏輯將缺少的鍵視為例外,請使用 try/except KeyError。對列表和陣列而言,如果負位置不應從尾端計數,請依照 0 <= index < len(table) 驗證索引。對 DataFrame 篩選結果,選取第一列前要先確認結果是否為空。各函式應採用一致的處理方式,讓呼叫端清楚知道缺少資料時會得到哨兵值、預設值,還是錯誤。

比較效能與實務取捨

字典依鍵查詢的平均時間複雜度為 O(1),列表或一維陣列則依位置以 O(1) 取值。DataFrame 布林篩選通常是 O(n),因為它會檢查各列;索引可支援依標籤存取,但成本和行為取決於索引的建置方式及資料形狀。這些複雜度描述無法預測每種輸入規模下的實際執行速度:建置成本、鍵的型別、資料配置、函式庫操作和記憶體都會產生影響。

請選擇符合鍵的形式和操作需求的最簡單結構:任意鍵用字典,密集位置用列表,數值陣列運算用 NumPy 陣列,具名表格操作用 DataFrame。若效能是決定因素,請使用有代表性的資料進行基準測試。也要考量記憶體:字典儲存鍵和值的對應關係,列表保存 Python 物件的參照,NumPy 陣列則儲存具型別的元素;實際用量會依資料和實作方式而異。若查詢表是從會變動的來源資料推導而來,請在來源資料變更時重建或更新查詢表,避免結果過時。