攝影或3C

Python: 如何利用dict.pop() 對字典重新排序? dict.pop() #刪除key,回傳value

說明 1:dict.pop() 的兩件事

  • 從字典刪除指定 key
  • 回傳該 key 對應的 value(這個回傳值就是我們要「搬家」再插入用的值)

執行這格觀察效果:

data = {'a': 1, 'b': 2}
val = data.pop('a')   # 刪除 'a'同時拿到它的 value
print('pop 回傳的值:', val)
print('pop 後的字典:', data)

# 把剛剛拿到的值再插回去
data['a'] = val
print('重新插入後的字典(a 會在最後):', data)

輸出結果:

說明 2:準備一個相像但簡化的字典

  • 目標:把「鍵名包含 向量 / vector / embedding」的項目移到字典最後
  • 只看「鍵名」,不看「值」內容
  • 像 basename 這種重要鍵名不含關鍵字,即使值裡有 vector 也不移動
data = {
    'basename': 'fixtureRepair_nl_vector_info.json',  
    # 重要資訊,鍵名不含向量關鍵字 -> 不移
    'index': 0,
    '向量(by gpt-4.1)': [0.12, -0.03, 0.8],          # 需要被移到最後
    '向量(by f-string)': [0.02, 0.03, 0.75],         # 需要被移到最後
    'desc': '值裡面可能有 vector,但我們不看值',
    'vector_norm': 0.98,                              # 需要被移到最後
    'meta': {'source': 'x'}
}
print('原始順序:')
data

輸出:

說明 3:設定關鍵字(大小寫不敏感)

keywords = ['向量', 'vector', 'embedding']
kw_lower = [k.lower() for k in keywords]
kw_lower

輸出:

說明 4:為何不要一邊遍歷一邊改字典?

  • 遍歷同時改動結構,容易跳鍵或出錯
  • 作法:先收集要移動的鍵,再統一處理
to_move = []
for k in list(data.keys()):          #  list(...) 先拍下當前鍵的快照
    if isinstance(k, str):           # 僅處理字串鍵
        kl = k.lower()
        if any(sub in kl for sub in kw_lower):
            to_move.append(k)

print('待移動的鍵:', to_move)

輸出:

說明 5:用 pop 拿出值,再插回末尾(達成「搬到最後」)

for k in to_move:
    v = data.pop(k)   # 1) 刪除該鍵並拿到 value
    data[k] = v       # 2) 重新插入 -> 會出現在字典末尾

print('搬移後的順序:')
data

輸出:

說明 6:觀念總結

  • pop 同時「刪除鍵並回傳值」,這個回傳值就是我們能「先拿出再插回」的關鍵
  • Python 3.7+ 的 dict 會保留插入順序,因此重新插入即代表「移到最後」
  • 先收集鍵再統一 pop/插入,避免邊遍歷邊修改
  • 只看鍵名是否含關鍵字,值中即使有關鍵字也不影響(例如 basename 的值含 vector 仍不會被移動)
  • 想要精準匹配就縮小關鍵字清單;想要寬鬆匹配就擴大清單或改用正則

推薦hahow線上學習python: https://igrape.net/30afN

封裝為函數:

# %%
from typing import Iterable

def move_keys_to_end(d: dict,
                     key_words: Iterable[str] = ('向量', 'vector', 'embedding'),
                     case_sensitive: bool = False):
    """
    在「當前字典」層級,把鍵名包含任一關鍵字的項目移到字典最後
    - d: 就地修改的字典
    - key_words: 關鍵字清單
    - case_sensitive: 是否大小寫敏感預設 False不敏感
    回傳同一個 d已就地修改
    """
    if not isinstance(d, dict):
        raise TypeError("d 必須是 dict")

    # 預處理大小寫
    if case_sensitive:
        # 大小寫敏感如實比較
        to_move = [k for k in list(d.keys())
                   if isinstance(k, str) and any(kw in k for kw in key_words)]
    else:
        # 大小寫不敏感全部轉小寫再比
        kw_lower = tuple(str(kw).lower() for kw in key_words)
        to_move = []
        for k in list(d.keys()):
            if isinstance(k, str):
                k_lower = k.lower()
                if any(kw in k_lower for kw in kw_lower):
                    to_move.append(k)

    # 依序 pop 再插回末尾
    for k in to_move:
        v = d.pop(k)
        d[k] = v
    return d

# 測試單層
data = {
    'basename': 'fixtureRepair-2025-03-21_nl_vector_info.json',
    '向量_Info': [0.1, 0.2],
    'Vector_Norm': 0.98,
    'embedding_used': True,
    'index': 0
}

print('原本順序:', list(data.keys()))
move_keys_to_end(data, key_words=('向量', 'vector', 'embedding'), case_sensitive=False)
print('大小寫不敏感後:', list(data.keys()))

# 再來一份以測大小寫敏感
data2 = {
    'basename': 'x',
    '向量_Info': [0.1, 0.2],
    'Vector_Norm': 0.98,     # 注意 V 是大寫
    'vector_norm': 0.97,     # 小寫
    'index': 0
}
print('原本順序2:', list(data2.keys()))
move_keys_to_end(data2, key_words=('vector',), case_sensitive=True)   # 只匹配小寫 'vector'
print('大小寫敏感後(只移小寫 vector):', list(data2.keys()))

輸出:

多一個inplcae參數:

from typing import Iterable
from copy import deepcopy

def move_keys_to_end_safe(d: dict,
                          key_words: Iterable[str] = ('向量', 'vector', 'embedding'),
                          case_sensitive: bool = False,
                          in_place: bool = False):
    """
    說明
        依鍵名包含關鍵字把該項目移到字典最後
    參數
        d: 原始字典
        key_words: 關鍵字
        case_sensitive: 大小寫敏感與否
        in_place: 是否就地修改False 時會建立淺拷貝True 則直接修改 d
    回傳
        修改後的字典 in_place=True回傳的是 d 自身否則是拷貝
    風險註記
        就地修改可能影響共用引用請酌量使用
    """
    if not isinstance(d, dict):
        raise TypeError("d 必須是 dict")

    target = d if in_place else d.copy()  # 淺拷貝需要遞迴處理時請用 deepcopy

    if case_sensitive:
        to_move = [k for k in list(target.keys())
                   if isinstance(k, str) and any(kw in k for kw in key_words)]
    else:
        kw_lower = tuple(str(kw).lower() for kw in key_words)
        to_move = []
        for k in list(target.keys()):
            if isinstance(k, str):
                k_lower = k.lower()
                if any(kw in k_lower for kw in kw_lower):
                    to_move.append(k)

    for k in to_move:
        v = target.pop(k)
        target[k] = v
    return target

# 示範不就地修改回傳新 dict
orig = {'A': 1, 'vector_x': 2, 'b': 3}
new1 = move_keys_to_end_safe(orig, key_words=('vector',), case_sensitive=False, in_place=False)
print('orig:', orig)
print('new1:', new1)

# 示範就地修改orig 會被改
orig2 = {'A': 1, 'vector_x': 2, 'b': 3}
new2 = move_keys_to_end_safe(orig2, key_words=('vector',), case_sensitive=False, in_place=True)
print('orig2(被改):', orig2)
print('new2(同一參考):', new2)

輸出:

推薦hahow線上學習python: https://igrape.net/30afN

儲蓄保險王

儲蓄險是板主最喜愛的儲蓄工具,最喜愛的投資理財工具則是ETF,最喜愛的省錢工具則是信用卡