ฟังก์ชัน sorted () ของ python รับประกันว่าเสถียรหรือไม่?


101

เอกสารไม่ได้รับประกันว่า มีสถานที่อื่นที่เป็นเอกสารหรือไม่?

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

วัตถุประสงค์: ฉันต้องการจัดเรียงตามคีย์หลักและคีย์รองในกรณีที่คีย์หลักเท่ากันในทั้งสองระเบียน หากรับประกันว่า sorted () มีเสถียรภาพฉันสามารถจัดเรียงบนคีย์รองจากนั้นเรียงลำดับบนคีย์หลักและได้ผลลัพธ์ที่ต้องการ

PS: เพื่อหลีกเลี่ยงความสับสนฉันใช้ความเสถียรในแง่ของ "การเรียงลำดับมีเสถียรภาพหากรับประกันว่าจะไม่เปลี่ยนลำดับสัมพัทธ์ขององค์ประกอบที่เปรียบเทียบเท่ากัน"

คำตอบ:


131

ใช่เจตนาของคู่มือนี้คือการรับประกันว่าsortedมีความเสถียรและแน่นอนว่ามันใช้อัลกอริทึมเดียวกับsortวิธีการ ฉันตระหนักดีว่าเอกสารไม่ชัดเจน 100% เกี่ยวกับตัวตนนี้ doc patches ได้รับการยอมรับอย่างมีความสุขเสมอ!


2
ฉันพบว่าถ้าฉันจัดเรียงสิ่งที่เพิ่มขึ้นหรือรายการเมื่อใดก็ตามที่คีย์การเรียงลำดับ "หลัก" เท่ากันจะลงเอยด้วยการจัดเรียงตามคีย์ "รอง" ตัวอย่างเช่นsorted([(1, 2), (1, 1)])ส่งกลับ[(1, 1), (1, 2)]แทนที่จะส่งคืนอินพุตเดิมในลำดับ / ลำดับเดียวกัน การรับประกันความเสถียรไม่ควรหมายความว่าควรส่งคืน[(1, 2), (1, 1)]อินพุตเดิมใช่หรือไม่ ในกรณีนี้คุณต้องพูดอย่างชัดเจนและพูดว่าsorted([(1, 2), (1, 1)], key=lambda t: t[0])
code_dredd

10
นี่คือสิ่งที่คาดหวังในกรณีนี้ไม่ใช่หรือ? Python จะเปรียบเทียบสิ่งทอผ่านองค์ประกอบทั้งหมดตามค่าเริ่มต้นไม่ใช่แค่ "หลัก" ตัวแรก หากคุณต้องการจัดเรียงเฉพาะองค์ประกอบแรกคุณสามารถส่งผ่านkeyพารามิเตอร์อย่างชัดเจน
Matias Grioni

2
@code_dredd นี่คือพฤติกรรมที่คาดไว้ จุดของการจัดเรียงแบบคงที่คือการจัดเรียงโดยใช้ "คีย์การเรียงลำดับ" แต่องค์ประกอบที่แตกต่างกันสองรายการที่มีคีย์การเรียงลำดับเดียวกันจะอยู่ในลำดับเดียวกัน คีย์การเรียงลำดับเริ่มต้นสำหรับทูเปิลคือองค์ประกอบทั้งหมดของทูเปิล
Guyarad

29

พวกเขามีความมั่นคง

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

ตัวอย่างเช่นถ้าคุณต้องการที่จะจัดเรียงวัตถุบนพื้นฐานของพวกเขาlast_name, first_nameคุณลักษณะที่คุณสามารถทำมันได้ในหนึ่งผ่าน:

sorted_list= sorted(
    your_sequence_of_items,
    key= lambda item: (item.last_name, item.first_name))

ใช้ประโยชน์จากการเปรียบเทียบทูเพิล

คำตอบนี้ครอบคลุมคำถามเดิมตามที่เป็นอยู่ สำหรับคำถามเรียงลำดับที่เกี่ยวข้องต่อไปนั่นคืองูหลามเรียงลำดับวิธีการ


5
ซึ่งอาจมีผลที่ไม่ต้องการหากคุณต้องการย้อนกลับการจัดเรียง ตัวอย่างเช่นเมื่อจัดเรียงสินค้าคุณอาจต้องเรียงลำดับตามลำดับก่อน (จากน้อยไปหามาก) จากนั้นจึงเรียงตามราคา (จากน้อยไปหามาก) หากคุณย้อนกลับสิ่งนี้คุณต้องการเรียงลำดับตามลำดับจากมากไปหาน้อย แต่ราคาจากน้อยไปมาก วิธีนี้ใช้ไม่ได้กับโซลูชันนี้
Remco Wendt

2
@RemcoWendt: ไม่มีข้อกำหนดสำหรับสิ่งที่คุณอธิบาย ไม่ว่าในกรณีใด ๆ ให้พิจารณาkey= lambda item: (-item.rating, item.price)หรือจัดหา a cmpแทนการkeyโต้แย้ง ฉันยังไม่แน่ใจเกี่ยวกับจุดประสงค์ของความคิดเห็นของคุณ
tzot

1
อันที่จริงมันไม่ใช่ข้อกำหนด แต่ต้องการชี้ให้เห็นความแตกต่างเล็กน้อยนี้เมื่อคนอื่นอ่านสิ่งนี้และตัดสินใจเลือกระหว่างโซลูชันของคุณหรือใช้คุณสมบัติการเรียงลำดับที่เสถียรของ Python
Remco Wendt

ฉันเห็น. กล่าวอีกนัยหนึ่งการจัดเรียงตามคู่จะชัดเจนกว่าและเป็นที่นิยมมากกว่าเว้นแต่คุณจะสนใจเรื่องประสิทธิภาพ ฉันคิดว่าสองประเภทที่มั่นคงค่อนข้างเร็วกว่าการเรียงลำดับทีละคู่แม้ว่าความแตกต่างอาจเล็กน้อย -?
Sergey Orshanskiy

8
@tzot ฉันต้องการพูดถึงมีข้อกำหนดดังกล่าวเสมอสำหรับการเรียงลำดับที่มั่นคง ตัวอย่างเช่นฉันมีรายการทูเปิล (อัตราความคิดเห็น) ความคิดเห็นจะถูกบันทึกตามลำดับเวลาที่เกิดขึ้นและฉันต้องการจัดเรียงตามอัตราและรักษาลำดับเวลาอย่างไรก็ตามฉันไม่ได้บันทึก การประทับเวลาในรายการ พูดสั้น ๆ ก็คือฉันแค่ต้องการจัดเรียงรายการตามอัตราและเพื่อให้ความคิดเห็นเป็นลำดับเดียวกัน
wsysuper

4

เอกสารมีการเปลี่ยนแปลงในระหว่างนี้ ( ข้อผูกพันที่เกี่ยวข้อง ) และเอกสารปัจจุบันของsortedการรับประกันอย่างชัดเจน:

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

ส่วนหนึ่งของเอกสารนี้ถูกบันทึกอยู่ใน Python 2.7 และ Python 3.4 (+) เพื่อให้ใด ๆที่สอดคล้องกับการดำเนินงานของรุ่นภาษาที่ควรจะมีsortedเสถียรภาพ

โปรดทราบว่าสำหรับ CPython list.sortมีความเสถียรตั้งแต่Python 2.3

  • Tim Peters เขียนlist.sort()การใช้งานของเขาใหม่- อันนี้เป็น "การเรียงลำดับที่มั่นคง" (อินพุตที่เท่ากันจะปรากฏในลำดับเดียวกันในเอาต์พุต) และเร็วกว่าเดิม

ฉันไม่แน่ใจ 100% sortedทุกวันนี้มันใช้ง่ายlist.sortแต่ฉันไม่ได้ตรวจสอบประวัติ แต่มันก็เป็นไปได้ว่ามัน "เสมอ" list.sortที่ใช้


0

เอกสาร"มีอะไรใหม่" สำหรับ Python 2.4จะทำให้จุดที่ sorted () สร้างรายการก่อนอย่างมีประสิทธิภาพจากนั้นเรียก sort () บนเอกสารนั้นให้การรับประกันที่คุณต้องการแม้ว่าจะไม่อยู่ในเอกสาร "อย่างเป็นทางการ" ก็ตาม คุณสามารถตรวจสอบแหล่งที่มาได้หากคุณกังวลจริงๆ


1
คุณช่วยชี้ไปที่ที่มันบอกได้ไหม? มันบอกว่า sorted () "ทำงานเหมือน in-place list.sort ()" และ "a new form copy is sorted" แต่ฉันไม่เห็นมันบอกว่ามันใช้ sort () เป็นการภายใน
sundar - คืนสถานะ Monica

"สำเนา" ที่สร้างขึ้นคือรายการ (นั่นคือสิ่งที่คุณได้รับเป็นค่าส่งคืน) และ .ort () ถูกเรียกในรายการนั้นก่อนที่จะส่งคืน QED ไม่ไม่ใช่ข้อพิสูจน์ที่ใช้ไม่ได้ แต่จนกว่า Python จะมีมาตรฐานอย่างเป็นทางการคุณจะไม่ได้รับสิ่งนั้น
Peter Hansen

0

ตอนนี้เอกสาร Python 3.6 เกี่ยวกับการเรียงลำดับระบุว่า

ประเภทต่างๆได้รับการรับรองว่ามีเสถียรภาพ

นอกจากนี้ในเอกสารนั้นยังมีลิงค์ไปยังTimsort ที่เสถียรซึ่งระบุว่า

Timsort เป็นอัลกอริธึมการเรียงลำดับมาตรฐานของ Python ตั้งแต่เวอร์ชัน 2.3

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