วิธีการเรียงลำดับรายการ / ทูเปิลของรายการ / ทูเปิลตามองค์ประกอบที่ดัชนีที่กำหนด?


658

ฉันมีข้อมูลบางอย่างในรายการของรายการหรือรายการของ tuples เช่นนี้

data = [[1,2,3], [4,5,6], [7,8,9]]
data = [(1,2,3), (4,5,6), (7,8,9)]

และฉันต้องการจัดเรียงตามองค์ประกอบที่ 2 ในชุดย่อย ความหมายการเรียงลำดับตาม 2,5,8 ที่2อยู่ห่างจาก(1,2,3), จาก5 (4,5,6)วิธีทั่วไปในการทำเช่นนี้คืออะไร? ฉันควรจัดเก็บสิ่งอันดับหรือรายการในรายการ


51
ในเรื่องเกี่ยวกับ "ฉันควรจัดเก็บสิ่งอันดับหรือรายการในรายการของฉัน" กฎง่ายๆคือการทำให้สิ่งต่าง ๆ ไม่เปลี่ยนรูปให้มากที่สุด หากคุณไม่จำเป็นต้องแก้ไขรายการย่อยให้แทนที่พวกมันเป็นรายการ
Matthew Flaschen

คำตอบ:


1114
sorted_by_second = sorted(data, key=lambda tup: tup[1])

หรือ:

data.sort(key=lambda tup: tup[1])  # sorts in place

10
มีความคิดอย่างไรในการจัดเรียงที่ใหญ่กว่าให้เล็กลง?
billwild

63
@billwild: help (เรียงลำดับ) ย้อนกลับ = True
สตีเฟ่น

34
@Stephen โดยใช้ itemgetter เร็วขึ้นและง่ายขึ้น: key=itemgetter(1)และที่จุดเริ่มต้นของไฟล์:from operator import itemgetter
Joschua

3
@Cemre สำหรับตัวอย่างที่สองsortนี่คือวิธีการของListวัตถุของ Python ซึ่งได้รับฟังก์ชั่นแลมบ์ดาเป็นkeyพารามิเตอร์ของมัน คุณอาจตั้งชื่อมันเป็นtupหรือtหรืออะไรก็ได้ที่คุณชอบและมันจะยังใช้ได้อยู่ tupที่นี่ระบุดัชนีของ tuple ของรายการดังนั้น1หมายความว่าการเรียงลำดับจะดำเนินการโดยค่าที่สองของ tuples จากรายการดั้งเดิม ( 2, 5, 8)
สารสื่อประสาท

1
ฉันสงสัยอย่างไม่มั่นใจในคำกล่าวอ้างว่า "ใช้ itemgetter นั้นเร็วและง่ายกว่า" ในขณะที่ฉันกระทำถือว่าใช้งานง่ายlambdaวิธีการที่จะง่ายกว่า unintuitive itemgetterชั้นitemgetter ไม่แน่นอนดูเหมือนจะเร็วขึ้น ฉันอยากรู้ว่าทำไมถึงเป็นแบบนี้ ความสงสัยที่หยาบคายของฉันคือมีlambdaค่าใช้จ่ายที่ซ่อนเร้นในการจับตัวแปรท้องถิ่นทั้งหมดในบริบทปิดในขณะที่itemgetterอินสแตนซ์ไม่ tl; dr:ใช้ทุกitemgetterครั้งเพราะความเร็วชนะ
เซซิลแกงกะหรี่

236
from operator import itemgetter
data.sort(key=itemgetter(1))

37
นี่ควรเป็นคำตอบที่ยอมรับได้ ดูเพิ่มเติมชาร์ลี 's กำหนดเวลาที่โพสต์แสดงให้เห็นถึงitemgetterระดับการจัดเรียง126% เร็วกว่าค่าเฉลี่ยเทียบเท่าlambdaฟังก์ชั่น
เซซิลแกงกะหรี่

9
นอกจากนี้คุณยังสามารถเรียงลำดับตามดัชนีหลาย ๆ แบบได้เช่นdata.sort(key=itemgetter(3,1))
Michael Ohlrogge

57

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

reverse = True

และผลลัพธ์จะเป็นดังนี้:

data.sort(key=lambda tup: tup[1], reverse=True)

48

สำหรับการเรียงลำดับตามหลายเกณฑ์เช่นสำหรับองค์ประกอบที่สองและสามใน tuple ให้

data = [(1,2,3),(1,2,1),(1,1,4)]

และเพื่อกำหนดแลมบ์ดาที่ส่งกลับ tuple ที่อธิบายถึงลำดับความสำคัญเป็นต้น

sorted(data, key=lambda tup: (tup[1],tup[2]) )
[(1, 1, 4), (1, 2, 1), (1, 2, 3)]

28

คำตอบของสตีเฟ่นคือคำตอบที่ฉันใช้ เพื่อความสมบูรณ์นี่คือรูปแบบ DSU (ตกแต่งเรียงลำดับไม่ได้) พร้อมความเข้าใจในรายการ:

decorated = [(tup[1], tup) for tup in data]
decorated.sort()
undecorated = [tup for second, tup in decorated]

หรือยิ่งกระชับมากขึ้น:

[b for a,b in sorted((tup[1], tup) for tup in data)]

ดังที่ระบุไว้ในPython Sorting HowToสิ่งนี้ไม่จำเป็นตั้งแต่ Python 2.4 เมื่อมีฟังก์ชั่นหลักให้ใช้งาน


2
ดังนั้นคำตอบนี้มีประโยชน์สำหรับ Python 2.3-? มีการใช้งานที่ถูกต้องใน Python เวอร์ชันปัจจุบันมากกว่าซึ่งคุณอาจอธิบายรายละเอียดเล็กน้อย? ถ้าไม่ไม่ต้องกังวล ... เพิ่งผ่านไปเห็นสิ่งนี้และแก้วเหล้าเก่า ๆ ก็ต้องปั่นป่วนเล็กน้อย อย่างไรก็ตามไชโยและขอบคุณสำหรับการเดินกลับเข้าไปใน Python
mechanical_meat

19

เพื่อเรียงลำดับรายการของสิ่งอันดับ(<word>, <count>)สำหรับcountเรียงลำดับจากมากไปน้อยและwordเรียงตามตัวอักษร:

data = [
('betty', 1),
('bought', 1),
('a', 1),
('bit', 1),
('of', 1),
('butter', 2),
('but', 1),
('the', 1),
('was', 1),
('bitter', 1)]

ฉันใช้วิธีนี้:

sorted(data, key=lambda tup:(-tup[1], tup[0]))

และมันให้ผลลัพธ์กับฉัน:

[('butter', 2),
('a', 1),
('betty', 1),
('bit', 1),
('bitter', 1),
('bought', 1),
('but', 1),
('of', 1),
('the', 1),
('was', 1)]

1
เกิดอะไรขึ้นถ้า tup [1] เป็นสตริง
eric


9

itemgetter()ค่อนข้างเร็วกว่าlambda tup: tup[1]แต่การเพิ่มขึ้นค่อนข้างปานกลาง (ประมาณ 10 ถึง 25 เปอร์เซ็นต์)

(เซสชัน IPython)

>>> from operator import itemgetter
>>> from numpy.random import randint
>>> values = randint(0, 9, 30000).reshape((10000,3))
>>> tpls = [tuple(values[i,:]) for i in range(len(values))]

>>> tpls[:5]    # display sample from list
[(1, 0, 0), 
 (8, 5, 5), 
 (5, 4, 0), 
 (5, 7, 7), 
 (4, 2, 1)]

>>> sorted(tpls[:5], key=itemgetter(1))    # example sort
[(1, 0, 0), 
 (4, 2, 1), 
 (5, 4, 0), 
 (8, 5, 5), 
 (5, 7, 7)]

>>> %timeit sorted(tpls, key=itemgetter(1))
100 loops, best of 3: 4.89 ms per loop

>>> %timeit sorted(tpls, key=lambda tup: tup[1])
100 loops, best of 3: 6.39 ms per loop

>>> %timeit sorted(tpls, key=(itemgetter(1,0)))
100 loops, best of 3: 16.1 ms per loop

>>> %timeit sorted(tpls, key=lambda tup: (tup[1], tup[0]))
100 loops, best of 3: 17.1 ms per loop

โปรดดูโซลูชันการคัดแยก itemgetter สำหรับการเปลี่ยนแปลงอาร์กิวเมนต์ที่กลับกันของหลายคอลัมน์ที่นี่จากนั้นคุณต้องจัดเรียงการเรียงหลายขั้นตอนในแถว: stackoverflow.com/questions/14466068/…
Lorenz

6

@Stephen คำตอบคือตรงประเด็น! นี่คือตัวอย่างสำหรับการสร้างภาพข้อมูลที่ดีขึ้น

ตะโกนออกมาสำหรับแฟน ๆ ของ Ready Player One! =)

>>> gunters = [('2044-04-05', 'parzival'), ('2044-04-07', 'aech'), ('2044-04-06', 'art3mis')]
>>> gunters.sort(key=lambda tup: tup[0])
>>> print gunters
[('2044-04-05', 'parzival'), ('2044-04-06', 'art3mis'), ('2044-04-07', 'aech')]

keyเป็นฟังก์ชั่นที่จะถูกเรียกให้แปลงรายการของคอลเลกชันเพื่อเปรียบเทียบ .. เช่นcompareToวิธีการใน Java

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

ตัวอย่างด้านล่างเรากำลังเรียงลำดับรายการของ tuple ที่เก็บข้อมูลเกี่ยวกับเวลาของเหตุการณ์และชื่อนักแสดง

เรากำลังเรียงลำดับรายการนี้ตามเวลาที่เกิดเหตุการณ์ซึ่งเป็นองค์ประกอบที่ 0 ของ tuple

หมายเหตุ - s.sort([cmp[, key[, reverse]]]) เรียงลำดับรายการของที่อยู่ในสถานที่


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