ใน Python ฉันจะวนซ้ำพจนานุกรมในการเรียงลำดับคีย์ได้อย่างไร


211

มีฟังก์ชันที่มีอยู่ซึ่งลงท้ายด้วยต่อไปนี้โดยที่dเป็นพจนานุกรม:

return d.iteritems()

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

คำตอบ:


171

ยังไม่ได้ทดสอบสิ่งนี้อย่างกว้างขวาง แต่ทำงานใน Python 2.5.2

>>> d = {"x":2, "h":15, "a":2222}
>>> it = iter(sorted(d.iteritems()))
>>> it.next()
('a', 2222)
>>> it.next()
('h', 15)
>>> it.next()
('x', 2)
>>>

หากคุณคุ้นเคยกับการทำfor key, value in d.iteritems(): ...ซ้ำแทนที่จะใช้ตัววนซ้ำสิ่งนี้จะยังคงใช้ได้กับวิธีแก้ไขปัญหาข้างต้น

>>> d = {"x":2, "h":15, "a":2222}
>>> for key, value in sorted(d.iteritems()):
>>>     print(key, value)
('a', 2222)
('h', 15)
('x', 2)
>>>

ด้วย Python 3.x ให้ใช้d.items()แทนd.iteritems()การส่งคืนตัววนซ้ำ


29
ใช้.items()แทนiteritems(): ตามที่ @Claudiu กล่าวว่า iteritems ไม่สามารถใช้กับ Python 3.x ได้ แต่items()มีให้จาก Python 2.6
Remi

40
ไม่ชัดเจน ในความเป็นจริงitems()สร้างรายการและดังนั้นจึงใช้หน่วยความจำในขณะที่iteritems()เป็นหลักไม่ได้ใช้หน่วยความจำ สิ่งที่ใช้ส่วนใหญ่ขึ้นอยู่กับขนาดของพจนานุกรม นอกจากนี้หลามอัตโนมัติ 2 ถึง 3 หลามเครื่องมือการแปลง ( 2to3) จะดูแลการแปลงจากiteritems()ไปitems()จึงมีความจำเป็นที่จะต้องกังวลเกี่ยวกับเรื่องนี้
Eric O Lebigot

5
@HowerHell ใช้collections.OrderedDictแล้วคุณเรียงครั้งเดียวและรับรายการในการเรียงลำดับเสมอ
Mark Harviston

9
แต่ @EOL แม้ว่าiteritems()จะไม่ได้ใช้หน่วยความจำทุกอย่างจะต้องถูกดึงเข้าไปในหน่วยความจำsorted()ดังนั้นจึงไม่มีความแตกต่างระหว่างการใช้งานitems()และiteritems()ที่นี่หน่วยความจำที่ชาญฉลาด
Richard

8
@Richard: ในขณะที่มันเป็นความจริงที่องค์ประกอบทั้งหมดจะต้องดึงเข้าไปในหน่วยความจำพวกเขาจะถูกเก็บไว้สองครั้งด้วยitems()(ในรายการกลับมาitems()และในรายการเรียง) และเพียงครั้งเดียวกับiteritems()(ในรายการเรียงเท่านั้น)
Eric O Lebigot

83

ใช้sorted()ฟังก์ชั่น:

return sorted(dict.iteritems())

หากคุณต้องการตัววนซ้ำจริงเหนือผลลัพธ์ที่เรียงลำดับเนื่องจากsorted()ส่งคืนรายการให้ใช้:

return iter(sorted(dict.iteritems()))

ที่ล้มเหลวสำหรับฉัน: <type 'exceptionions.TypeError'>: iter () ส่งคืน non-iterator ของ type 'list'
mike

อาจเป็นเพราะคุณใช้ "dict" เป็นชื่อตัวแปร "dict" จริง ๆ แล้วเป็นชื่อประเภทของพจนานุกรม เพียงใช้ชื่ออื่นเช่น "mydict" ที่นี่และ voila
utku_karatas

1
ยังไม่ทำงาน คุณจัดเรียงเป็นบวก () ส่งกลับตัววนซ้ำอื่นซึ่งตรงข้ามกับรายการปกติหรือไม่?
ไมค์

ข้อยกเว้นนี้เกิดขึ้นเมื่อใดและที่ไหน คุณสามารถวนซ้ำรายการได้โดยไม่มีปัญหา

1
เห็นด้วยกระโดด ฉันไม่คิดว่าฉันเคยโทร. ถัดไป () โดยตรงยกเว้นเมื่อข้ามบรรทัดในไฟล์ โซลูชัน iter (เรียงลำดับ (dict.iteritems ())) ของเราจบลงด้วยการทำสำเนาของ dict ทั้งหมดในหน่วยความจำที่ "เรียงลำดับ (" เวทีแล้วดังนั้นประโยชน์ iterator หลักดูเหมือนจะหายไป :)

39

คีย์ของ dict ถูกเก็บไว้ใน hashtable เพื่อให้เป็น 'ลำดับธรรมชาติ' ของพวกเขานั่นคือ psuedo-random การสั่งซื้ออื่นใด ๆ เป็นแนวคิดของผู้บริโภคของ dict

เรียง () จะส่งคืนรายการเสมอไม่ใช่ dict ถ้าคุณส่งมันเป็น dict.items () (ซึ่งสร้างรายการของ tuples) มันจะส่งคืนรายการของ tuples [(k1, v1), (k2, v2), ... ] ซึ่งสามารถใช้เป็นวง ในทางที่มากเหมือน dict แต่มันไม่ได้อยู่ใน dict !

foo = {
    'a':    1,
    'b':    2,
    'c':    3,
    }

print foo
>>> {'a': 1, 'c': 3, 'b': 2}

print foo.items()
>>> [('a', 1), ('c', 3), ('b', 2)]

print sorted(foo.items())
>>> [('a', 1), ('b', 2), ('c', 3)]

ต่อไปนี้ให้ความรู้สึกเหมือน dict ในวง แต่ไม่ใช่มันเป็นรายการของ tuples ที่ถูกแตกออกเป็น k, v:

for k,v in sorted(foo.items()):
    print k, v

เทียบเท่ากับ:

for k in sorted(foo.keys()):
    print k, foo[k]

โอเค แต่ฉันไม่ต้องการ Dict หรือ List ฉันต้องการ Iterator ฉันจะบีบบังคับให้กลายเป็น Iterator ได้อย่างไร
ไมค์

2
sorted(foo.keys())ดีกว่าเทียบเท่าsorted(foo)เนื่องจากพจนานุกรมส่งคืนคีย์ของพวกเขาเมื่อมีการวนซ้ำ (ด้วยความได้เปรียบของการไม่ถูกบังคับให้สร้างfoo.keys()รายการกลางอาจขึ้นอยู่กับวิธีsorted()การนำไปใช้กับ iterables)
Eric O Lebigot

สงสัยว่าจะดีกว่าสำหรับความเร็วและ / หรือหน่วยความจำk in sorted(foo.keys()):ที่ดึงกุญแจหรือfor k,v in sorted(foo.items()):คืนสำเนาของรายการพจนานุกรมที่ฉันเดาsorted(foo.keys())
CrandellWS

1
@CrandellWS: วิธีที่ดีที่สุดในการตอบคำถามเวลาคือด้วยโมดูลPython timeit
Peter Rowell

1
@frank - คำตอบสั้น ๆ : ไม่ dict คืออาร์เรย์ที่มีคีย์จริงเป็นค่าแฮชของค่าของคีย์ที่ให้มา แม้ว่าการใช้งานบางอย่างอาจจะคาดเดาได้อย่างเป็นธรรมและบางคนยังอาจทำให้สัญญานี้ผมนับบนอะไรเมื่อมันมาถึงการสั่งซื้อกัญชา ดูโพสต์นี้สำหรับข้อมูลเพิ่มเติมเกี่ยวกับพฤติกรรม 3.6+ โดยเฉพาะหมายเหตุคำตอบแรก
Peter Rowell

31

คำตอบของ Greg ถูกต้อง โปรดทราบว่าใน Python 3.0 คุณต้องทำ

sorted(dict.items())

ตามที่iteritemsจะหายไป


ที่ล้มเหลวสำหรับฉัน: <type 'exceptionions.TypeError'>: iter () ส่งคืน non-iterator ของ type 'list'
mike

3
"อย่าใช้รถยนต์เพราะในอนาคตเราจะมี hoverboards"
JJ

7

คุณสามารถใช้งานOrderedDictPython 2.7 ได้แล้วในตอนนี้:

>>> from collections import OrderedDict
>>> d = OrderedDict([('first', 1),
...                  ('second', 2),
...                  ('third', 3)])
>>> d.items()
[('first', 1), ('second', 2), ('third', 3)]

ที่นี่คุณมีอะไรใหม่หน้า 2.7 รุ่นและOrderedDict API


นั่นจะส่งคืนคีย์ค่าตามลำดับที่แทรก - ไม่ใช่เรียงตามลำดับ (เช่นตัวอักษร)
Tony Suffolk 66

5

โดยทั่วไปแล้วคนหนึ่งอาจเรียงลำดับ dict ดังนี้:

for k in sorted(d):
    print k, d[k]

สำหรับกรณีเฉพาะในคำถามโดยมี "การแทนที่แบบแทนที่" สำหรับ d.iteritems () ให้เพิ่มฟังก์ชันดังนี้:

def sortdict(d, **opts):
    # **opts so any currently supported sorted() options can be passed
    for k in sorted(d, **opts):
        yield k, d[k]

และดังนั้นบรรทัดสุดท้ายจึงเปลี่ยนจาก

return dict.iteritems()

ถึง

return sortdict(dict)

หรือ

return sortdict(dict, reverse = True)

5
>>> import heapq
>>> d = {"c": 2, "b": 9, "a": 4, "d": 8}
>>> def iter_sorted(d):
        keys = list(d)
        heapq.heapify(keys) # Transforms to heap in O(N) time
        while keys:
            k = heapq.heappop(keys) # takes O(log n) time
            yield (k, d[k])


>>> i = iter_sorted(d)
>>> for x in i:
        print x


('a', 4)
('b', 9)
('c', 2)
('d', 8)

วิธีนี้ยังคงมีการเรียงลำดับ O (N บันทึก N) อย่างไรก็ตามหลังจาก heapify เชิงเส้นสั้น ๆ มันให้ผลผลิตรายการในการเรียงลำดับตามที่ไปทำให้ทฤษฎีมีประสิทธิภาพมากขึ้นเมื่อคุณไม่ต้องการรายการทั้งหมด


4

หากคุณต้องการที่จะจัดเรียงตามลำดับที่รายการเสียบแทนของคำสั่งของกุญแจที่คุณควรมีลักษณะที่จะหลามของcollections.OrderedDict (Python 3 เท่านั้น)


3

เรียงลำดับส่งกลับรายการดังนั้นข้อผิดพลาดของคุณเมื่อคุณพยายามที่จะทำซ้ำมากกว่า แต่เพราะคุณไม่สามารถสั่ง dict คุณจะต้องจัดการกับรายการ

ฉันไม่รู้ว่าบริบทของโค้ดของคุณใหญ่กว่าอะไร แต่คุณสามารถลองเพิ่มตัววนซ้ำไปยังรายการผลลัพธ์ได้ อาจจะเป็นแบบนี้:

return iter(sorted(dict.iteritems()))

แน่นอนคุณจะได้รับผลตอบแทน tuples ในขณะนี้เพราะเรียงลำดับหัน dict ของคุณลงในรายการของสิ่งอันดับ

ตัวอย่าง: บอกว่า dict ของคุณคือ: {'a':1,'c':3,'b':2} เรียงลำดับเปลี่ยนเป็นรายการ:

[('a',1),('b',2),('c',3)]

ดังนั้นเมื่อคุณวนซ้ำในรายการคุณจะได้รับกลับมา (ในตัวอย่างนี้) tuple ที่ประกอบด้วยสตริงและจำนวนเต็ม แต่อย่างน้อยคุณจะสามารถทำซ้ำได้


2

สมมติว่าคุณกำลังใช้ CPython 2.x และมีพจนานุกรม mydict ขนาดใหญ่จากนั้นการใช้ sort (mydict) จะช้าลงเนื่องจากการเรียงลำดับจะสร้างรายการเรียงลำดับของคีย์ของ mydict

ในกรณีนี้คุณอาจต้องการดูแพคเกจ ordereddict ของฉันซึ่งรวมถึงการนำ C ไปใช้sorteddictใน C โดยเฉพาะอย่างยิ่งถ้าคุณต้องข้ามรายการเรียงลำดับของคีย์หลายครั้งในระยะต่าง ๆ (เช่นจำนวนองค์ประกอบ) ของอายุการใช้งานพจนานุกรม

http://anthon.home.xs4all.nl/Python/ordereddict/

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