วิธีที่ดีที่สุดในการจัดเรียงผกผันในสกาล่าคืออะไร


137

วิธีที่ดีที่สุดในการจัดเรียงผกผันในสกาล่าคืออะไร? ฉันคิดว่าสิ่งต่อไปนี้ค่อนข้างช้า

list.sortBy(_.size).reverse

มีวิธี conveinient ใช้ sortBy แต่รับเรียงกลับกัน? sortWithผมค่อนข้างจะไม่จำเป็นต้องใช้


1
วิธีแก้ปัญหาด้านล่างนั้นดีมาก แต่ฉันก็ยังหาวิธีดั้งเดิมของคุณในการอ่านที่ง่ายกว่านี้ ฉันได้ตรวจสอบแล้วว่ามีข้อบกพร่องในการคำนวณสำหรับวิธีการเขียนนี้ตามที่คุณสงสัย การทดสอบที่ฉันทำคือ: val clock = new Timer (1 ถึง 1e6.toInt) .sorted (สั่ง [Int] .reverse) clock.addLap ("วิธีที่ถูกต้อง") (1 ถึง 1e6.toInt) clock.addLap ("วิธีที่ไม่ถูกต้อง") println (clock.toString) [วิธีที่ถูกต้อง, lap = 76, ระยะเวลา = 76] | [วิธีที่ไม่ถูกต้องรอบ = 326, ระยะเวลา = 250]
Khoa

คำตอบ:


242

อาจมีวิธีที่ชัดเจนในการเปลี่ยนเครื่องหมายถ้าคุณเรียงตามค่าตัวเลขบางอย่าง

list.sortBy(- _.size)

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

list.sorted(theOrdering.reverse)

หากการสั่งซื้อที่คุณต้องการย้อนกลับเป็นการสั่งซื้อโดยปริยายคุณสามารถรับได้โดยสั่ง [การสั่งซื้อ [A]] (ประเภทที่คุณสั่งซื้อ) หรือการสั่งซื้อที่ดีกว่า [A] นั่นจะเป็น

list.sorted(Ordering[TheType].reverse)

sortBy เป็นเหมือนการใช้ Ordering.by ดังนั้นคุณสามารถทำได้

list.sorted(Ordering.by(_.size).reverse)

อาจไม่ใช่การเขียนที่สั้นที่สุด (เทียบกับลบ) แต่เจตนาชัดเจน

ปรับปรุง

บรรทัดสุดท้ายไม่ทำงาน ที่จะยอมรับ_ในความต้องการที่จะรู้ว่าคอมไพเลอร์ที่พิมพ์เรามีการสั่งซื้อเพื่อให้สามารถพิมพ์Ordering.by(_.size) _มันอาจจะดูเหมือนว่าจะเป็นชนิดขององค์ประกอบของรายการ def sorted[B >: A](ordering: Ordering[B])แต่ตอนนี้ไม่เป็นเช่นนั้นเป็นลายเซ็นของเรียงเป็น การสั่งซื้ออาจจะเปิดAแต่ยังอยู่ในบรรพบุรุษของA(คุณอาจใช้byHashCode : Ordering[Any] = Ordering.by(_.hashCode)) และแน่นอนความจริงที่ว่ารายการนั้นแปรปรวนบังคับให้ลายเซ็นนี้ หนึ่งสามารถทำได้

list.sorted(Ordering.by((_: TheType).size).reverse)

แต่นี่เป็นสิ่งที่น่ายินดีน้อยกว่ามาก


มีประโยชน์มาก - ฉันไม่แน่ใจว่าฉันถามคำถามโง่ ๆ หรือไม่ แต่ฉันได้เรียนรู้มากมายจากคำตอบของคุณ!
schmmd

ยกเว้นว่ามันใช้งานไม่ได้ ฉันไม่ควรตอบเมื่อไม่มี REPL สะดวก ดูการอัพเดต
Didier Dupont

และเพื่อเรียงลำดับบนสนามที่สองให้คืนค่า tuple:list.sortBy(x => (-x.size, x.forTiesUseThisField))
Brent Faust

2
แทนที่จะlist.sorted(Ordering.by((_: TheType).size).reverse)คิดว่าlist.sorted(Ordering.by[TheType, Int](_.size).reverse)มันชัดเจนกว่า (แต่นานกว่า) สำหรับประเด็น veiw ของฉัน
เชอร์รี่

5
ผมเองชอบlist.sortBy(_.size)(Ordering[Int].reverse)ยัง
dtech


27

อาจจะสั้นลงอีกเล็กน้อย:

def Desc[T : Ordering] = implicitly[Ordering[T]].reverse

List("1","22","4444","333").sortBy( _.size )(Desc)

19

peasy ง่าย ๆ (อย่างน้อยในกรณีของsize):

scala> val list = List("abc","a","abcde")
list: List[java.lang.String] = List(abc, a, abcde)

scala> list.sortBy(-_.size)
res0: List[java.lang.String] = List(abcde, abc, a)

scala> list.sortBy(_.size)
res1: List[java.lang.String] = List(a, abc, abcde)

9

sortByมีพารามิเตอร์โดยนัยordซึ่งให้การสั่งซื้อ

def sortBy [B] (f: (A) ⇒ B)(implicit ord: Ordering[B]): List[A]

ดังนั้นเราสามารถกำหนดOrderingวัตถุของตัวเอง

scala> implicit object Comp extends Ordering[Int] {
 | override def compare (x: Int, y: Int): Int = y - x
 | }
defined module Comp

List(3,2,5,1,6).sortBy(x => x)
res5: List[Int] = List(6, 5, 3, 2, 1)

9

ทั้งสองsortWithและsortByมีไวยากรณ์ขนาดกะทัดรัด:

case class Foo(time:Long, str:String)

val l = List(Foo(1, "hi"), Foo(2, "a"), Foo(3, "X"))

l.sortWith(_.time > _.time)  // List(Foo(3,X), Foo(2,a), Foo(1,hi))

l.sortBy(- _.time)           // List(Foo(3,X), Foo(2,a), Foo(1,hi))

l.sortBy(_.time)             // List(Foo(1,hi), Foo(2,a), Foo(3,X))

ฉันพบคนsortWithที่เข้าใจง่ายกว่า



1

ความเป็นไปได้อีกอย่างในกรณีที่คุณส่งผ่านฟังก์ชั่นที่คุณอาจไม่สามารถแก้ไขโดยตรงไปยัง Arraybuffer ผ่าน sortWith เช่น:

val buf = collection.mutable.ArrayBuffer[Int]()
buf += 3
buf += 9
buf += 1

// the sort function (may be passed through from elsewhere)
def sortFn = (A:Int, B:Int) => { A < B }

// the two ways to sort below
buf.sortWith(sortFn)                        // 1, 3, 9
buf.sortWith((A,B) => { ! sortFn(A,B) })    // 9, 3, 1

0

นี่คือรหัสของฉัน;)

val wordCounts = logData.flatMap(line => line.split(" "))
                        .map(word => (word, 1))
                        .reduceByKey((a, b) => a + b)

wordCounts.sortBy(- _._2).collect()

1
สิ่งนี้ไม่ถูกต้อง แต่ส่วนที่น่าสนใจ (บรรทัดที่สอง) จะถูกจมลงโดยบรรทัดที่ไม่จำเป็นก่อนหน้า โดยทั่วไปจุดที่นี่คือวิธีหนึ่งที่จะทำการจัดเรียงย้อนกลับคือการปฏิเสธค่าการเรียง
Carl-Eric Menzel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.