Python กำหนดว่าจะสร้างคีย์หรือผนวกองค์ประกอบกับคีย์ได้อย่างไร


161

ฉันมีพจนานุกรมที่ว่างเปล่า ชื่อ: dict_x มันคือการมีกุญแจที่มีค่าเป็นรายการ

จากการวนซ้ำแยกกันฉันได้รับคีย์ (เช่น:) key_123และไอเท็ม (tuple) เพื่อวางในรายการdict_xค่าkey_123ของ

หากคีย์นี้มีอยู่แล้วฉันต้องการผนวกรายการนี้ หากคีย์นี้ไม่มีอยู่ฉันต้องการสร้างด้วยรายการเปล่าแล้วต่อท้ายหรือต่อเติมหรือสร้างด้วย tuple ในนั้น

ในอนาคตเมื่อคีย์นี้ปรากฏขึ้นอีกครั้งเนื่องจากมีอยู่ฉันต้องการให้ผนวกค่าอีกครั้ง

รหัสของฉันประกอบด้วย:

รับคีย์และค่า

ดูว่าไม่dict_xสำคัญที่มีอยู่ใน

และถ้าไม่สร้างมัน: dict_x[key] == []

หลังจากนั้น: dict_x[key].append(value)

นี่เป็นวิธีที่จะทำหรือไม่ ฉันจะลองใช้try/exceptบล็อคได้หรือไม่

คำตอบ:


254

การใช้dict.setdefault():

dic.setdefault(key,[]).append(value)

ช่วย (dict.setdefault) :

    setdefault(...)
        D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D

4
ฉันเคยทำสิ่งนี้โดยdict_x[key] = [some_value] if not dict_x.has_key(key) else dict_x[key] + [some_value]คำตอบนี้แสดงให้เห็นวิธีที่ดีกว่า ในความเป็นจริงมันจะได้รับset()เป็นข้อโต้แย้งและช่วยให้คุณใช้add()วิธีการ ...
fatih_dur

66

ต่อไปนี้เป็นวิธีการต่างๆในการทำเช่นนี้เพื่อให้คุณสามารถเปรียบเทียบว่ามีลักษณะอย่างไรและเลือกสิ่งที่คุณชอบ ฉันสั่งให้พวกเขาในแบบที่ฉันคิดว่าเป็น"pythonic"มากที่สุดและแสดงความคิดเห็นข้อดีและข้อเสียที่อาจไม่ชัดเจนในการมองครั้งแรก:

การใช้collections.defaultdict:

import collections
dict_x = collections.defaultdict(list)

...

dict_x[key].append(value)

จุดเด่น: ประสิทธิภาพที่ดีที่สุดน่าจะเป็น ข้อด้อย: ไม่มีใน Python 2.4.x

การใช้dict().setdefault():

dict_x = {}

...

dict_x.setdefault(key, []).append(value)

ข้อด้อย: การสร้างlist()s ที่ไม่ได้ใช้อย่างไม่มีประสิทธิภาพ

การใช้try ... except:

dict_x = {}

...

try:
    values = dict_x[key]
except KeyError:
    values = dict_x[key] = []
values.append(value)

หรือ:

try:
    dict_x[key].append(value)
except KeyError:
    dict_x[key] = [value]

สวัสดีทำไมคุณคิดว่า. setdefault สร้างพจนานุกรมที่ไม่จำเป็นขึ้นมา?
Phil

2
ฉันไม่คิดว่า.setdefault()จะสร้างพจนานุกรมที่ไม่จำเป็น ฉันคิดว่าฉันกำลังสร้างlists (ie []) ที่ไม่จำเป็นในอาร์กิวเมนต์ที่สองของ.setdefault()ที่ไม่เคยใช้ถ้าkeyมีอยู่แล้ว ฉันสามารถใช้dict.setdefault()(เพื่อประโยชน์ของการแฮ็กคีย์อย่างมีประสิทธิภาพ) และใช้ตัวแปรเพื่อนำlists ที่ไม่ได้ใช้มาใช้ใหม่แต่เพิ่มโค้ดอีกสองสามบรรทัด
antak

1
IIRC ใน Python รายการว่างในความเท่าเทียมถือเป็นค่าคงที่ในระดับ bytecode แต่สิ่งนี้ต้องการการยืนยันจากกูรู bytecode (หรือเพียงแค่ใช้โมดูล disas)
gaborous

การใช้การ.setdefaultสร้างปกติdictซึ่งการค้นหาคีย์ที่หายไปจะส่งผลในKeyErrorขณะที่การcollections.defaultdict(list)สร้างdictคีย์การค้นหาที่ขาดหายไปจะแทรกว่างเปล่าlist- ฉันคิดว่าคุณควรเลือกตามพฤติกรรมที่คุณต้องการ
Chris_Rands

ฉันลองอะไรที่คล้ายกับ collection.defaultdict ในรหัสของฉันเองและมันมีผลข้างเคียงที่ไม่คาดคิด ตัวอย่างเช่นให้พิจารณาการแลกเปลี่ยน IDLE ต่อไปนี้: >>> list_dict = defaultdict (รายการ) >>> len (list_dict) 0 >>> len (list_dict [0]) 0 >>> len (list_dict) 1 ปรากฏว่าเมื่อ Python เรียกใช้ ค่าเริ่มต้นจะเพิ่มคีย์ไปที่พจนานุกรมโดยที่คุณไม่ต้องตั้งค่าอย่างแข็งขันซึ่งจะสร้างรายการเปล่าจำนวนมากหากใช้ค่าเริ่มต้นมาก ฉันจะม้วนฟังก์ชั่นเสื้อคลุมของฉันสำหรับพจนานุกรมไม่มีประสิทธิภาพ แต่หวังว่าจะสามารถคาดเดาได้มากขึ้น
RDBury

26

คุณสามารถใช้ค่าเริ่มต้นสำหรับคำสั่งนี้

from collections import defaultdict
d = defaultdict(list)
d['key'].append('mykey')

สิ่งนี้มีประสิทธิภาพมากกว่าที่setdefaultคุณไม่ได้สร้างรายการใหม่ที่คุณไม่ได้ใช้ ทุกการเรียกsetdefaultไปจะสร้างรายการใหม่แม้ว่ารายการนั้นจะมีอยู่แล้วในพจนานุกรม


14

คุณสามารถใช้defaultdictcollectionsใน

ตัวอย่างจาก doc:

s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = defaultdict(list)
for k, v in s:
    d[k].append(v)

0
dictionary['key'] = dictionary.get('key', []) + list_to_append

1
คุณควรอธิบายถึงข้อได้เปรียบ (น้อยมาก) ที่มีอยู่ในข้อยกเว้นบางประการ เช่นเดียวกับรหัสก็ไม่ชัดเจนว่าทำไมต้องมีคำตอบเพิ่มเติม
Davis Herring

สวัสดีทางเลือกเดียวที่ไม่มีการนำเข้าเพิ่มเติม สิ่งนี้สามารถทำได้อย่างชัดเจนด้วยคำสั่ง if ฉันแค่แนะนำทางเลือกโดยใช้พลังของ. get () แทนที่จะใช้ dict []
Tomas Silva Ebensperger

ด้านบนสองคำตอบที่พูดถึงสองวิธีที่แตกต่างกันกับการนำเข้าไม่มี (แม้จะไม่ได้dict.get)
Davis Herring
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.