จะเก็บคีย์ / ค่าในลำดับเดียวกับที่ประกาศไว้ได้อย่างไร?


320

ฉันมีพจนานุกรมที่ฉันประกาศในลำดับเฉพาะและต้องการเก็บไว้ในลำดับนั้นตลอดเวลา คีย์ / ค่าไม่สามารถเก็บตามลำดับจริง ๆ ได้ฉันแค่ต้องการมันตามลำดับที่ฉันประกาศ

ดังนั้นถ้าฉันมีพจนานุกรม:

d = {'ac': 33, 'gw': 20, 'ap': 102, 'za': 321, 'bs': 10}

มันไม่ได้อยู่ในลำดับนั้นถ้าฉันดูหรือทำซ้ำมันมีวิธีใดบ้างที่จะทำให้แน่ใจว่า Python จะรักษาลำดับที่ชัดเจนที่ฉันประกาศคีย์ / ค่าไว้หรือไม่

คำตอบ:


229

ตั้งแต่ Python 3.6 เป็นต้นไปdictประเภทมาตรฐานจะเก็บรักษาลำดับการแทรกตามค่าเริ่มต้น

การกำหนด

d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}

จะส่งผลให้พจนานุกรมพร้อมปุ่มตามลำดับที่ระบุไว้ในซอร์สโค้ด

สิ่งนี้สามารถทำได้โดยการใช้อาเรย์อย่างง่ายที่มีจำนวนเต็มสำหรับตารางแฮชกระจัดกระจายซึ่งดัชนีจำนวนเต็มเหล่านั้นไปยังอาเรย์อื่นที่เก็บคู่ของคีย์ - ค่า (รวมถึงแฮชที่คำนวณได้) อาร์เรย์หลังนั้นเกิดขึ้นเพื่อจัดเก็บรายการตามลำดับการแทรกและชุดค่าผสมทั้งหมดใช้หน่วยความจำน้อยกว่าการใช้งานใน Python 3.5 และก่อนหน้า ดูโพสต์ความคิดดั้งเดิมโดย Raymond Hettingerสำหรับรายละเอียด

ใน 3.6 นี้ยังถือว่าเป็นรายละเอียดการใช้งาน; เห็นมีอะไรใหม่ในหลาม 3.6เอกสาร :

ด้านการรักษาลำดับของการใช้งานใหม่นี้ถือว่าเป็นรายละเอียดการใช้งานและไม่ควรพึ่งพา (อาจเปลี่ยนแปลงได้ในอนาคต แต่เป็นที่ต้องการที่จะมีการใช้งาน dict ใหม่นี้ในภาษาสำหรับรุ่นไม่กี่ก่อนที่จะเปลี่ยนข้อมูลจำเพาะภาษา เพื่อมอบอำนาจความหมายเพื่อรักษาคำสั่งซื้อสำหรับการใช้งาน Python ปัจจุบันและอนาคตทั้งหมดนี้ยังช่วยรักษาความเข้ากันได้ย้อนหลังกับภาษารุ่นเก่าที่คำสั่งการสุ่มซ้ำยังคงมีผลเช่น Python 3.5)

Python 3.7 ยกระดับรายละเอียดการใช้งานนี้เป็นข้อกำหนดภาษาดังนั้นตอนนี้จึงจำเป็นต้องdictรักษาลำดับในการใช้งาน Python ทั้งหมดที่เข้ากันได้กับเวอร์ชันนั้นหรือใหม่กว่า ดูคำวินิจฉัยโดย BDFL

คุณอาจยังต้องการใช้collections.OrderedDict()คลาสในบางกรณีเนื่องจากมีฟังก์ชันการทำงานเพิ่มเติมบางอย่างที่ด้านบนของdictประเภทมาตรฐาน เช่นการย้อนกลับ (สิ่งนี้ขยายไปถึงวัตถุมุมมอง ) และสนับสนุนการจัดเรียงใหม่ (ผ่านmove_to_end()วิธีการ )


แต่น่าเสียดายที่นี้ไม่เกี่ยวข้องกับการพจนานุกรมสร้าง พจนานุกรมที่ระบุเช่นเดียวกับตัวอย่างในรหัสไม่รับประกันว่าจะรักษาลำดับเดียวกัน ซึ่งหมายความว่าคุณต้องสร้าง dict ที่ว่างเปล่าและแทรกแต่ละองค์ประกอบด้วยตนเองหากคุณต้องการควบคุมการสั่งซื้อ
naught101

8
@ naught101: ไม่มีนี้ไม่นำไปใช้กับการสร้าง Dict ในหลาม 3.7 ขึ้นไปโดยใช้จอแสดงผล Dict ดังแสดงในคำถามที่มีการประกันเพื่อรายการคีย์เหล่านั้นในการสั่งซื้อ คู่ค่าคีย์ที่เขียนจะถูกแทรกจากซ้ายไปขวาเพราะภาษาข้อมูลจำเพาะรับประกันว่า : ถ้าลำดับที่คั่นด้วยเครื่องหมายจุลภาคคีย์ / คู่ตัวเลขจะได้รับพวกเขาได้รับการประเมินจากซ้ายไปขวาเพื่อกำหนดรายการของพจนานุกรม dict()เอกสารยังรวมถึงตัวอย่าง
Martijn Pieters

175
from collections import OrderedDict
OrderedDict((word, True) for word in words)

มี

OrderedDict([('He', True), ('will', True), ('be', True), ('the', True), ('winner', True)])

หากค่าคือTrue(หรือวัตถุที่ไม่เปลี่ยนรูปอื่น ๆ ) คุณสามารถใช้:

OrderedDict.fromkeys(words, True)

2
แน่นอนน่าสังเกตว่าส่วน 'ไม่เปลี่ยนรูป' ไม่ใช่กฎที่ยากและรวดเร็วที่ Python จะบังคับใช้ - เป็นเพียงความคิดที่ดีเท่านั้น
lvc

11
โปรดทราบว่าโซลูชันที่ชอบ: จะOrderedDict(FUTURE=[], TODAY=[], PAST=[])ไม่ทำงานเมื่อกล่าวถึง aproach: OrderedDict([('FUTURE', []), ('TODAY', []), ('PAST', [])])จะรักษาความสงบเรียบร้อย
andilabs

2
@andi ฉันมีปัญหาอื่นเมื่อใช้ jsonify ดูเหมือนว่า OrderedDict จะหายไปมันจึงเป็นคำสั่งเมื่อสร้างข้อมูล json แล้วจะแก้ปัญหานี้ได้อย่างไร
tyan

github.com/pallets/flask/issues/974สิ่งนี้สามารถใช้ในการแก้ปัญหา ..
Tyan

5
Python3.7 ตอนนี้มีการสั่งซื้อตามคำบอกโดยค่าเริ่มต้น mail.python.org/pipermail/python-dev/2017-December/151283.html
sertsedat

167

แทนที่จะอธิบายส่วนทางทฤษฎีฉันจะยกตัวอย่างง่ายๆ

>>> from collections import OrderedDict
>>> my_dictionary=OrderedDict()
>>> my_dictionary['foo']=3
>>> my_dictionary['aol']=1
>>> my_dictionary
OrderedDict([('foo', 3), ('aol', 1)])
>>> dict(my_dictionary)
{'foo': 3, 'aol': 1}

16
มีวิธีในการมอบหมายให้สั่ง OrderedDict เหมือนประเภท Dict หรือไม่
tyan

2
OrderedDictแน่นอนแก้ปัญหา แต่ ... ในตัวอย่างนี้คุณจะได้รับผลลัพธ์เดียวกันโดยใช้พจนานุกรมมาตรฐาน
Tonechas

2
@Tonechas: ฉันแค่ลองตัวอย่างด้วยพจนานุกรมมาตรฐานและได้{'aol': 1, 'foo': 3}ดังนั้นฉันคิดว่ามันเป็นตัวอย่างที่ดี
twasbrillig

4
มีบทเรียนสำหรับทุกคน: มันถูกค้นพบ (ฉันคิดว่าประมาณ 2.4 รีลีส) ว่าการแฮชที่คาดเดาได้ของ Python อาจทำให้เกิดช่องโหว่ด้านความปลอดภัยดังนั้นตอนนี้จึงไม่มีอะไรรับประกันได้ว่าแม้แต่การทำงานของรหัสเดียวกัน Dict
holdenweb

1
@tyan คุณสามารถเรียกOrderedDict.update()กับ iterable d1.upate([(key1, val1), (key2, val2)])มีคู่ค่าคีย์:
Ruud Althuizen

37

โปรดทราบว่าคำตอบนี้ใช้กับเวอร์ชัน python ก่อนหน้า python3.7 CPython 3.6 รักษาลำดับการแทรกภายใต้สถานการณ์ส่วนใหญ่เป็นรายละเอียดการใช้งาน เริ่มจาก Python3.7 เป็นต้นไปจะมีการประกาศว่าการใช้งานต้องรักษาลำดับการแทรกให้สอดคล้อง


พจนานุกรมภาษาไพ ธ อนไม่มีการเรียงลำดับ หากคุณต้องการพจนานุกรมคำสั่งให้ลองcollections.OrderedDict

โปรดทราบว่า OrderedDict ได้รับการแนะนำในไลบรารีมาตรฐานใน python 2.7 ถ้าคุณมีรุ่นเก่าของงูหลามคุณสามารถหาสูตรสำหรับพจนานุกรมสั่งซื้อในActiveState


ดูโพสต์ของ @ martijn ด้านบน ตั้งแต่ python 3.6 เป็นต้นไป dict รองรับการเรียงลำดับการแทรก
tpk

13

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

คุณสามารถใช้รายการของวัตถุ (2 องค์ประกอบ tuple ในกรณีง่าย ๆ หรือแม้กระทั่งคลาส) และเพิ่มรายการต่อท้าย จากนั้นคุณสามารถใช้การค้นหาเชิงเส้นเพื่อค้นหารายการในนั้น

อีกทางหนึ่งคุณสามารถสร้างหรือใช้โครงสร้างข้อมูลอื่นที่สร้างขึ้นโดยมีเจตนาเพื่อรักษาความสงบเรียบร้อย


พจนานุกรมจะใช้ลำดับที่ทำให้การค้นหามีประสิทธิภาพในที่สุดใครบางคนก็ชี้ให้เห็น
scharette

7

ฉันเจอโพสต์นี้ในขณะที่พยายามหาวิธีให้ OrderedDict ทำงาน PyDev สำหรับ Eclipse ไม่พบ OrderedDict เลยดังนั้นฉันจึงตัดสินใจที่จะสร้างค่าคีย์ของพจนานุกรมของฉันเพราะฉันต้องการให้พวกเขาได้รับคำสั่ง เมื่อฉันต้องการส่งออกรายการของฉันฉันแค่ทำซ้ำผ่านค่าของ tuple และเสียบ 'key' ที่ทำซ้ำจาก tuple เข้าในพจนานุกรมเพื่อดึงค่าของฉันตามลำดับที่ฉันต้องการ

ตัวอย่าง:

test_dict = dict( val1 = "hi", val2 = "bye", val3 = "huh?", val4 = "what....")
test_tuple = ( 'val1', 'val2', 'val3', 'val4')
for key in test_tuple: print(test_dict[key])

มันค่อนข้างยุ่งยาก แต่ฉันก็กดครั้งและมันก็เป็นวิธีแก้ปัญหาที่ฉันคิดขึ้นมา

หมายเหตุ: รายการของวิธีการที่คนอื่นแนะนำไม่สมเหตุสมผลกับฉันจริงๆเพราะรายการต่าง ๆ ได้รับคำสั่งและจัดทำดัชนี (และยังเป็นโครงสร้างที่แตกต่างจากพจนานุกรม)


ทางออกที่ดี ฉันจะใช้มันเพื่อเขียน json ไปยังไฟล์เสมอในลำดับเดียวกัน
Hrvoje T

6

คุณไม่สามารถทำสิ่งที่คุณต้องการด้วยพจนานุกรม คุณได้d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}สร้างพจนานุกรมแล้ว ฉันพบว่าไม่มีวิธีที่จะรักษาความสงบเรียบร้อยเมื่อมันถูกสร้างขึ้นแล้ว สิ่งที่ฉันทำคือการสร้างไฟล์ json แทนด้วยวัตถุ:

{"ac":33,"gw":20,"ap":102,"za":321,"bs":10}

ฉันใช้:

r = json.load(open('file.json'), object_pairs_hook=OrderedDict)

ใช้แล้ว:

print json.dumps(r)

เพื่อตรวจสอบ


1
ดังนั้นทำไมไม่เริ่มต้นด้วย OrderedDict จากรายการ? ไฟล์ JSON ไม่ได้เพิ่มอะไรเลยที่นี่
Martijn Pieters

ใช่รายการมีประโยชน์มากกว่าในการรักษาความสงบเรียบร้อย แต่คำตอบนั้นเกี่ยวกับคำถามเกี่ยวกับการสั่งซื้อพจนานุกรม เพียงแค่ให้ผู้คนรู้เกี่ยวกับข้อ จำกัด ในการใช้พจนานุกรมและให้พวกเขาทำงานได้หากพวกเขาต้องการใช้พจนานุกรมด้วยเหตุผลบางอย่าง
nealous3

1
แต่ส่วนนั้นถูกครอบคลุมโดยคำตอบที่เก่ากว่าย้อนหลังไปถึงปี 2012
Martijn Pieters

3
from collections import OrderedDict
list1 = ['k1', 'k2']
list2 = ['v1', 'v2']
new_ordered_dict = OrderedDict(zip(list1, list2))
print new_ordered_dict
# OrderedDict([('k1', 'v1'), ('k2', 'v2')])

ปัญหาหลักที่ไม่ dict อีกต่อไปมันเป็นรายการของสิ่งอันดับ
Oleg

2

อีกทางเลือกหนึ่งคือการใช้ Pandas dataframeเนื่องจากเป็นการรับประกันคำสั่งซื้อและตำแหน่งดัชนีของรายการในโครงสร้างคล้าย dict


1

โดยทั่วไปแล้วคุณสามารถออกแบบการเรียนว่าพฤติกรรมเช่นพจนานุกรมส่วนใหญ่จะดำเนินการตามวิธีการ__contains__, __getitem__, __delitem__, __setitem__และบางมากขึ้น คลาสนั้นสามารถมีลักษณะการทำงานใด ๆ ที่คุณต้องการตัวอย่างเช่นการทำตัวซ้ำตัวเรียงลำดับไว้เหนือคีย์ ...


1

หากคุณต้องการมีพจนานุกรมตามลำดับที่เฉพาะเจาะจงคุณยังสามารถสร้างรายการของรายการโดยที่รายการแรกจะเป็นกุญแจสำคัญและรายการที่สองจะมีค่าและจะมีลักษณะเช่นนี้

>>> list =[[1,2],[2,3]]
>>> for i in list:
...     print i[0]
...     print i[1]

1
2
2
3

7
นั่นไม่ใช่ "พจนานุกรม" เพราะคุณไม่สามารถค้นหารายการด้วยคีย์ของพวกเขาโดยไม่ต้องค้นหาในคอลเล็กชันทั้งหมด (ใช้เวลา O (n))
BHSPitMonkey

1
ใช่มันไม่ได้เป็นพจนานุกรม แต่ขึ้นอยู่กับสถานการณ์มันสามารถให้ทางออกที่ถูกต้องปัญหาของโปสเตอร์ต้นฉบับ
SunSparc

เขาไม่ได้พูดอย่างที่เราต้องการเพียงแค่ต้องการสั่งให้พวกเขา =) เช่นเคยมีหลายวิธีในการทำสิ่งหนึ่ง
pelos

1

ฉันมีปัญหาคล้ายกันเมื่อพัฒนาโครงการ Django ฉันไม่สามารถใช้ OrderedDict ได้เพราะฉันใช้ python เวอร์ชั่นเก่าดังนั้นวิธีแก้ไขก็คือใช้คลาส SortedDict ของ Django:

https://code.djangoproject.com/wiki/SortedDict

เช่น,

from django.utils.datastructures import SortedDict
d2 = SortedDict()
d2['b'] = 1
d2['a'] = 2
d2['c'] = 3

หมายเหตุ: คำตอบนี้มีต้นกำเนิดมาจาก 2011 หากคุณมีการเข้าถึง Python เวอร์ชัน 2.7 หรือสูงกว่าคุณควรมีสิทธิ์เข้าถึงมาตรฐานตอนนี้collections.OrderedDictซึ่งมีตัวอย่างมากมายที่ผู้อื่นให้ไว้ในเธรดนี้


0

คุณสามารถทำสิ่งเดียวกันกับที่ฉันทำกับพจนานุกรม

สร้างรายการและพจนานุกรมว่างเปล่า:

dictionary_items = {}
fields = [['Name', 'Himanshu Kanojiya'], ['email id', 'hima@gmail.com']]
l = fields[0][0]
m = fields[0][1]
n = fields[1][0]
q = fields[1][1]
dictionary_items[l] = m
dictionary_items[n] = q
print dictionary_items
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.