วิธีการจัดเรียงรายการใน Scala ตามสองฟิลด์?


101

วิธีการจัดเรียงรายการใน Scala ตามสองฟิลด์ในตัวอย่างนี้ฉันจะจัดเรียงตาม lastName และ firstName?

case class Row(var firstName: String, var lastName: String, var city: String)

var rows = List(new Row("Oscar", "Wilde", "London"),
                new Row("Otto",  "Swift", "Berlin"),
                new Row("Carl",  "Swift", "Paris"),
                new Row("Hans",  "Swift", "Dublin"),
                new Row("Hugo",  "Swift", "Sligo"))

rows.sortBy(_.lastName)

ฉันลองสิ่งนี้

rows.sortBy(_.lastName + _.firstName)

แต่มันไม่ได้ผล ดังนั้นฉันจึงอยากรู้วิธีแก้ปัญหาที่ดีและง่าย

คำตอบ:


216
rows.sortBy(r => (r.lastName, r.firstName))

4
จะเกิดอะไรขึ้นถ้าเราต้องการย้อนกลับการจัดเรียงใน lastName แล้วเรียงลำดับตามธรรมชาติใน firstName?
Sachin K

14
@SachinK: คุณต้องสร้างของคุณเองOrderingสำหรับRowชั้นเรียนและใช้มันด้วยsortedวิธีการเช่นนี้: rows.sorted(customOrdering). นอกจากนี้คุณยังสามารถใช้กำหนดเองOrderingสำหรับการเช่นนี้Tuple2 rows.sortBy(r => (r.lastName, r.firstName))( Ordering.Tuple2(Ordering.String.reverse, Ordering.String) )
senia

5
@SachinK: คุณสามารถใช้customOrderingเป็นOrdering[Row]ด้วยตนเองหรือใช้Ordering.byเช่นนี้val customOrdering = Ordering.by ((r: แถว) => (r.lastName, r.firstName)) (Ordering.Tuple2 (Ordering.String.reverse, Ordering.String)) `
senia

1
ยอดเยี่ยม. หรือจะเรียงจากมากไปหาน้อยrows.sortBy(r => (-r.field1, -r.field2))
Brent Faust

@BrentFaust คุณไม่สามารถใช้-กับString. คุณควรใช้Ordering::reverseวิธีนี้: rows.sortBy(r => (r.lastName, r.firstName))(implicitly[Ordering[(String, String)]].reverse).
senia

12
rows.sortBy (row => row.lastName + row.firstName)

หากคุณต้องการจัดเรียงตามชื่อที่ผสานเช่นในคำถามของคุณหรือ

rows.sortBy (row => (row.lastName, row.firstName))

ถ้าคุณต้องการจัดเรียงตาม lastName ก่อนแล้วจึงเลือก firstName; เกี่ยวข้องกับชื่อที่ยาวขึ้น (Wild, Wilder, Wilderman)

ถ้าคุณเขียน

rows.sortBy(_.lastName + _.firstName)

ด้วย 2 ขีดเส้นใต้วิธีการนี้คาดหวังสองพารามิเตอร์:

<console>:14: error: wrong number of parameters; expected = 1
       rows.sortBy (_.lastName + _.firstName)
                               ^

1
ลำดับของสิ่งนี้อาจไม่เหมือนกับการเรียงลำดับตามชื่อแรกตามด้วยนามสกุล
Marcin

1
โดยเฉพาะเมื่อนามสกุลมีความยาวแตกต่างกัน
Luigi Plinge

7

โดยทั่วไปหากคุณใช้อัลกอริทึมการเรียงลำดับที่เสถียรคุณสามารถจัดเรียงตามคีย์เดียวจากนั้นจึงเรียงลำดับถัดไป

rows.sortBy(_.firstName).sortBy(_.lastName)

ผลลัพธ์สุดท้ายจะถูกจัดเรียงตามนามสกุลจากนั้นที่เท่ากันตามชื่อ


แน่ใจหรือว่า scala sortByใช้การจัดเรียงแบบเสถียร มิฉะนั้นคำตอบนี้จะไม่มีความหมาย
om-nom-nom

1
@ om-nom-nom: scala-lang.org/api/current/scala/util/Sorting$.html QuickSort ถูกกำหนดไว้สำหรับประเภทค่าเท่านั้นใช่
Marcin

1
rowsเป็นรายการที่ไม่เปลี่ยนรูปและsortByส่งคืนค่าใหม่แทนที่จะเปลี่ยนรูปแบบที่ใช้งานได้ (แม้ในคลาสที่เปลี่ยนแปลงไม่ได้) ดังนั้นนิพจน์ที่สองของคุณเป็นเพียงการจัดเรียงรายการที่ไม่ได้เรียงลำดับเดิม
Luigi Plinge

3
Scala ภายใต้ประทุนของวิธี sortBy ใช้ java.util.Arrays.sort ซึ่งสำหรับอาร์เรย์ของวัตถุรับประกันว่าจะมีเสถียรภาพ ใช่วิธีนี้ถูกต้อง (นี่ถูกตรวจสอบใน Scala 2.10)
Marcin Pieciukiewicz

1
มันน่าสนใจที่จะคิดถึงประสิทธิภาพของสิ่งนี้กับการเรียงลำดับเดียวโดยที่สร้างทูเพิล ด้วยวิธีนี้เห็นได้ชัดว่าคุณไม่จำเป็นต้องสร้างสิ่งเหล่านั้น แต่ด้วยวิธีทูเพิลคุณจะต้องเปรียบเทียบชื่อที่นามสกุลตรงกันเท่านั้น แต่ฉันคิดว่ามันไม่สำคัญ - หากคุณกำลังเขียนโค้ดที่มีความสำคัญต่อประสิทธิภาพคุณไม่ควรใช้ sortBy เลย!
AmigoNico

-3

บางทีนี่อาจใช้งานได้เฉพาะกับรายการสิ่งทอเท่านั้น แต่

scala> var zz = List((1, 0.1), (2, 0.5), (3, 0.6), (4, 0.3), (5, 0.1))
zz: List[(Int, Double)] = List((1,0.1), (2,0.5), (3,0.6), (4,0.3), (5,0.1))

scala> zz.sortBy( x => (-x._2, x._1))
res54: List[(Int, Double)] = List((3,0.6), (2,0.5), (4,0.3), (1,0.1), (5,0.1))

ดูเหมือนจะได้ผลและเป็นวิธีง่ายๆในการแสดงออก


แต่ใช้ไม่ได้กับสตริงซึ่งเป็นสิ่งที่ OP กำลังจัดเรียง
The Archetypal Paul

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

@honk: โซลูชันก่อนหน้านี้ใช้งานไม่ได้จริง (AFAICT) ในรายการ Tuples ถ้าฉันไม่ใช่มือใหม่ของ Scala บางทีฉันอาจจะเข้าใจวิธีปรับเปลี่ยนวิธีแก้ปัญหาก่อนหน้านี้ให้ใช้งานได้ในกรณีนั้น แต่วันนี้ฉันไม่ทำ ฉันคิดว่าคำตอบของฉันอาจช่วยให้มือใหม่ Scala คนอื่นทำสิ่งเดียวกันกับที่ฉันพยายามทำ
spreinhardt

@ user3508605: ขอขอบคุณสำหรับความตั้งใจที่จะมีส่วนร่วม อย่างไรก็ตามแนวคิดของ Stack Overflow คือการมีคำถามเกี่ยวกับปัญหาเฉพาะ (ตามที่เป็นอยู่ในกรณีนี้) และคำตอบที่กล่าวถึงปัญหาเฉพาะเหล่านั้น (และเฉพาะปัญหาเหล่านั้น) คำตอบของคุณเป็นทางออกสำหรับปัญหาอื่น ดังนั้นจึงเป็นสถานที่ที่ไม่ถูกต้องในการโพสต์ หากคุณคิดว่าคำตอบของคุณมีค่าก็ให้ถามคำถามใหม่ อธิบายปัญหาที่เกี่ยวข้องของคุณในคำถามใหม่แล้วโพสต์คำตอบของคุณที่นั่น สุดท้ายอย่าลืมลบคำตอบของคุณที่นี่ ขอบคุณสำหรับความร่วมมือ!
บีบแตร

@honk: ได้เลยฉันจะย้ายคำตอบไปเป็นคำถามแยกต่างหาก และถ้าฉันสามารถกำหนดให้คุณเพิ่มความคิดเห็นในคำตอบก่อนหน้าสำหรับคำถามนี้ (จาก Marcin) ดูเหมือนว่าจะผิด (ฉันไม่มีคะแนนความน่าเชื่อถือเพียงพอที่จะโพสต์ได้) ตัวอย่างในคำตอบนั้นจะเรียงลำดับทีละคีย์จากนั้นเรียงลำดับอีกครั้งด้วยคีย์อื่นซึ่งจะกำจัดผลลัพธ์ของการเรียงลำดับแรกได้อย่างมีประสิทธิภาพ อย่างน้อยก็ในรายการ Tuples ที่มี
spreinhardt
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.