Apa cara terbaik untuk mengurutkan terbalik dalam skala?

142

Apa cara terbaik untuk melakukan pengurutan terbalik dalam skala? Saya membayangkan berikut ini agak lambat.

list.sortBy(_.size).reverse

Apakah ada cara yang mudah untuk menggunakan sortBy tetapi mendapatkan pengurutan terbalik? Saya lebih suka tidak perlu menggunakan sortWith.

schmmd
sumber
1
solusi di bawah ini semuanya sangat bagus tetapi saya masih menemukan cara asli Anda untuk melakukan ini lebih sederhana untuk dibaca. Saya telah memverifikasi bahwa ada kekurangan komputasi pada cara penulisan ini seperti yang Anda duga. Tes yang saya lakukan adalah seperti ini: val clock = new Timer (1 to 1e6.toInt) .sorted (Ordering [Int] .reverse) clock.addLap ("cara yang benar") (1 to 1e6.toInt) .sorted.reverse clock.addLap ("salah cara") println (clock.toString) [cara yang benar, putaran = 76, dur. = 76] | [cara yang salah, putaran = 326, dur. = 250]
Khoa

Jawaban:

247

Mungkin ada cara yang jelas untuk mengubah tanda, jika Anda mengurutkan berdasarkan beberapa nilai numerik

list.sortBy(- _.size)

Secara lebih umum, pengurutan dapat dilakukan dengan metode yang diurutkan dengan Pengurutan implisit, yang dapat Anda buat secara eksplisit, dan Pengurutan memiliki kebalikan (bukan daftar terbalik di bawah). Anda dapat melakukannya

list.sorted(theOrdering.reverse)

Jika pengurutan yang ingin Anda balikkan adalah pengurutan implisit, Anda bisa mendapatkannya dengan [Pengurutan [A]] secara implisit (A tipe tempat Anda memesan) atau Pengurutan [A] yang lebih baik. Itu akan menjadi

list.sorted(Ordering[TheType].reverse)

sortBy seperti menggunakan Ordering.by, jadi Anda bisa melakukannya

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

Mungkin bukan yang terpendek untuk menulis (dibandingkan dengan minus) tetapi tujuannya jelas

Memperbarui

Baris terakhir tidak berfungsi. Untuk menerima _in Ordering.by(_.size), kompilator perlu mengetahui tipe mana yang kita pesan, sehingga ia dapat mengetik _. Tampaknya itu akan menjadi jenis elemen daftar, tetapi tidak demikian, karena tanda tangan diurutkan def sorted[B >: A](ordering: Ordering[B]). Pengurutan mungkin aktif A, tetapi juga pada leluhur mana pun A(Anda mungkin menggunakan byHashCode : Ordering[Any] = Ordering.by(_.hashCode)). Dan memang, fakta bahwa daftar adalah kovarian memaksa tanda tangan ini. Bisa dilakukan

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

tapi ini jauh lebih tidak menyenangkan.

Didier Dupont
sumber
Sangat membantu - Saya tidak yakin apakah saya mengajukan pertanyaan bodoh, tetapi saya belajar banyak dari jawaban Anda!
schmmd
Kecuali itu tidak berhasil. Saya seharusnya tidak menjawab ketika saya tidak memiliki REPL yang berguna. Lihat pembaruan.
Didier Dupont
Dan untuk mengurutkan bidang sekunder, kembalikan tupel:list.sortBy(x => (-x.size, x.forTiesUseThisField))
Brent Faust
2
Alih-alih list.sorted(Ordering.by((_: TheType).size).reverse)menganggapnya list.sorted(Ordering.by[TheType, Int](_.size).reverse)lebih jelas (tetapi lebih lama) untuk poin pandangan saya.
Cherry
5
Saya pribadi list.sortBy(_.size)(Ordering[Int].reverse)juga suka .
dtech
115
list.sortBy(_.size)(Ordering[Int].reverse)
incrop
sumber
27

mungkin untuk mempersingkatnya sedikit:

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

List("1","22","4444","333").sortBy( _.size )(Desc)
Bruno Bieth
sumber
19

Mudah sekali (setidaknya dalam kasus 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)
om-nom-nom
sumber
10

Keduanya sortWithdan sortBymemiliki sintaks yang ringkas:

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))

Saya menemukan yang sortWithlebih mudah dimengerti.

Jus12
sumber
9

sortBymemiliki parameter implisit ordyang menyediakan pengurutan

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

jadi, kita bisa mendefinisikan Orderingobjeknya sendiri

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)
4e6
sumber
9
val list = List(2, 5, 3, 1)
list.sortWith(_>_) -> res14: List[Int] = List(5, 3, 2, 1)
list.sortWith(_<_) -> res14: List[Int] = List(1, 2, 3, 5)
Tomek Kozlowski
sumber
Tidak menjawab pertanyaan itu.
tilde
1

Kemungkinan lain dalam kasus di mana Anda meneruskan fungsi yang mungkin tidak dapat Anda ubah secara langsung ke Arraybuffer melalui sortWith misalnya:

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
Chris
sumber
0

ini kode saya;)

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

wordCounts.sortBy(- _._2).collect()
Anxo P
sumber
1
Ini tidak salah, tetapi bagian yang menarik (baris kedua) tenggelam oleh baris yang tidak dibutuhkan sebelumnya. Pada dasarnya, poin di sini adalah bahwa salah satu cara untuk melakukan pengurutan terbalik adalah dengan meniadakan nilai pengurutan.
Carl-Eric Menzel