Python สร้างพจนานุกรมรายการ


214

ฉันต้องการสร้างพจนานุกรมที่มีค่าเป็นรายการ ตัวอย่างเช่น:

{
  1: ['1'],
  2: ['1','2'],
  3: ['2']
}

ถ้าฉันทำ:

d = dict()
a = ['1', '2']
for i in a:
    for j in range(int(i), int(i) + 2): 
        d[j].append(i)

ฉันได้รับ KeyError เพราะ d [... ] ไม่ใช่รายการ ในกรณีนี้ฉันสามารถเพิ่มรหัสต่อไปนี้หลังจากที่ได้รับมอบหมายของ a เพื่อเริ่มต้นพจนานุกรม

for x in range(1, 4):
    d[x] = list()

มีวิธีที่ดีกว่าในการทำเช่นนี้? ให้บอกว่าฉันไม่รู้กุญแจที่ฉันต้องการจนกว่าฉันจะอยู่ในforวงที่สอง ตัวอย่างเช่น:

class relation:
    scope_list = list()
...
d = dict()
for relation in relation_list:
    for scope_item in relation.scope_list:
        d[scope_item].append(relation)

ทางเลือกจะถูกแทนที่

d[scope_item].append(relation)

กับ

if d.has_key(scope_item):
    d[scope_item].append(relation)
else:
    d[scope_item] = [relation,]

วิธีที่ดีที่สุดในการจัดการกับสิ่งนี้คืออะไร? เป็นการดีที่การผนวกจะ "ทำงานได้" มีวิธีที่จะแสดงหรือไม่ว่าฉันต้องการพจนานุกรมของรายการที่ว่างเปล่าแม้ว่าฉันจะไม่ทราบว่าทุกคีย์เมื่อฉันสร้างรายการครั้งแรกหรือไม่?

คำตอบ:


278

คุณสามารถใช้defaultdict :

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> a = ['1', '2']
>>> for i in a:
...   for j in range(int(i), int(i) + 2):
...     d[j].append(i)
...
>>> d
defaultdict(<type 'list'>, {1: ['1'], 2: ['1', '2'], 3: ['2']})
>>> d.items()
[(1, ['1']), (2, ['1', '2']), (3, ['2'])]

1
พจนานุกรมอื่น ๆ ภายใต้collectionsโมดูลยังทำงานด้วยวิธีนี้เช่นcollections.OrderedDictกัน
txsaw1

2
โอ้ มันเยี่ยมมาก และคุณไม่จำเป็นต้องเริ่มต้นเป็น '= []' สิ่งที่ดี!
Wilmer E. Henao

1
NameError: name 'a' is not defined
S Andrew

51

คุณสามารถสร้างมันได้ด้วย list comprehension ดังนี้:

>>> dict((i, range(int(i), int(i) + 2)) for i in ['1', '2'])
{'1': [1, 2], '2': [2, 3]}

และสำหรับส่วนที่สองของคำถามของคุณให้ใช้defaultdict

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

>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

32

คุณสามารถใช้setdefault:

d = dict()
a = ['1', '2']
for i in a:
    for j in range(int(i), int(i) + 2): 
        d.setdefault(j, []).append(i)

print d  # prints {1: ['1'], 2: ['1', '2'], 3: ['2']}

setdefaultฟังก์ชันที่มีชื่อค่อนข้างแปลก ๆ จะบอกว่า "รับค่าด้วยคีย์นี้หรือถ้าไม่มีคีย์นั้นให้เพิ่มค่านี้แล้วส่งคืน"

ในขณะที่คนอื่นชี้ให้เห็นอย่างถูกต้องdefaultdictเป็นตัวเลือกที่ดีและทันสมัยกว่า setdefaultยังคงมีประโยชน์ใน Python เวอร์ชันเก่า (ก่อนหน้า 2.5)


2
ใช้งานได้ แต่โดยทั่วไปแล้วจะนิยมใช้ defaultdict เมื่อพร้อมใช้งาน
David Z

@ David ใช่ setdefault ไม่ใช่การออกแบบที่ยอดเยี่ยมที่สุดขอโทษด้วย - มันแทบจะเป็นทางเลือกที่ดีที่สุด ฉันคิดว่าเรา (ผู้มอบหมาย Python) แลกชื่อเสียงโดยรวมของเรากับชุดสะสมค่าเริ่มต้นแม้ว่า ;-)
Alex Martelli

@DavidZ, setdefault แตกต่างจาก defaultdict เนื่องจากมีความยืดหยุ่นมากกว่า: อื่น ๆ คุณจะระบุค่าเริ่มต้นที่แตกต่างกันสำหรับคีย์พจนานุกรมที่แตกต่างกันอย่างไร
Alex Gidan

@AlexGidan นั้นจริง แต่ไม่เกี่ยวข้องกับคำถามนี้โดยเฉพาะ
David Z

คำตอบนี้ยังมีประโยชน์เมื่อคุณต้องการ OrderedDict และค่าเริ่มต้น
nimcap

2

คำถามของคุณได้รับคำตอบแล้ว แต่ IIRC คุณสามารถแทนที่บรรทัดเช่น:

if d.has_key(scope_item):

ด้วย:

if scope_item in d:

นั่นคือdการอ้างอิงd.keys()ในการก่อสร้างนั้น บางครั้งdefaultdictไม่ใช่ตัวเลือกที่ดีที่สุด (ตัวอย่างเช่นหากคุณต้องการรันโค้ดหลายบรรทัดหลังจากที่elseเกี่ยวข้องกับข้างต้นif) และฉันพบว่าinไวยากรณ์อ่านง่ายขึ้น


2

โดยส่วนตัวฉันใช้ JSON เพื่อแปลงสิ่งต่าง ๆ เป็นสายอักขระและย้อนกลับ เงื่อนไขที่ฉันเข้าใจ

import json
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
mydict = {}
hash = json.dumps(s)
mydict[hash] = "whatever"
print mydict
#{'[["yellow", 1], ["blue", 2], ["yellow", 3], ["blue", 4], ["red", 1]]': 'whatever'}

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