Wie sortiere ich ein Array in Scala?

80

Ich kann sehen, dass sich ein Sortierobjekt Sortingmit einer Quicksort- Methode quickSortdarauf befindet.

Was wäre ein Codebeispiel für die Verwendung eines Arrays von Objekten beliebigen Typs? Es sieht so aus, als müsste ich eine Implementierung des OrderableMerkmals übergeben, bin mir aber der Syntax nicht sicher.

Außerdem würde ich Antworten bevorzugen, die dies auf die "Scala-Art" tun. Ich weiß, dass ich nur eine Java-Bibliothek verwenden kann.

Dan Gravell
quelle

Antworten:

32

Sorting.quickSort deklariert Funktionen zum Aufnehmen eines Arrays von Zahlen oder Strings, aber ich gehe davon aus, dass Sie eine Liste von Objekten Ihrer eigenen Klassen sortieren möchten?

Die Funktion, von der ich denke, dass Sie sie betrachten, ist

quickSort [K](a : Array[K])(implicit view$1 : (K) => Ordered[K]) : Unit

Wenn ich das richtig lese, bedeutet dies, dass die Objekte im Array die OrderedEigenschaft haben müssen . Ihre Klasse muss also erweitert Ordered(oder eingemischt) werden und daher die compareMethode dieses Merkmals implementieren .

Um ein Beispiel aus dem Buch abzureißen:

class MyClass(n: Int) extends Ordered[MyClass] {
   ...
  def compare(that: MyClass) =
    this.n - that.n
}

Wenn Sie also ein Array [MyClass] haben, sollte Sorting.quickSort funktionieren.

Skaffman
quelle
Ja, das ist der eine. Es macht Sinn, jetzt weisen Sie darauf hin. Wie würde ich es einmischen?
Dan Gravell
Siehe Bearbeiten. Sie entweder erweitern , wie mein Beispiel, oder die Verwendung „Klasse MyClass erstreckt Other mit bestellt [MyClass]“, was eine Verwechslung in ist.
Skaffman
Vielen Dank. Ich denke, ich werde Letzteres tun.
Dan Gravell
6
Um nicht pedantisch zu sein, aber ... Ihre Klasse muss Ordered nicht erweitern. Es reicht aus, wenn Ihre Klasse eine Ansicht (auch als implizite Konvertierung bezeichnet) auf etwas erweitert, das Ordered erweitert.
Kim Stebel
99

Mit Scala 2.8 oder höher ist Folgendes möglich:

List(3,7,5,2).sortWith(_ < _)

das verwendet java.util.Arrays.sort , eine Implementierung von quicksort.

adelarsq
quelle
2
Mit impliziter Reihenfolge noch kürzer: Liste (3,7,5,2) .sortiert nach scala.collection.immutable.LinearSeq
Utgarda
Woher wissen wir, dass sortWith java.util.Arrays.sort verwendet? Gibt es eine Referenz dafür?
Deepkimo
Dies ist ein bisschen anders als die ursprüngliche Frage. Es funktioniert sicherlich, eine neue sortierte Liste (oder ein Array, wie in der ursprünglichen Frage gestellt) zu erstellen, aber sortWith gibt ein neues Objekt zurück, anstatt die ursprüngliche Liste oder das Array an Ort und Stelle zu sortieren.
Rphutchinson
56

Heutzutage funktioniert dieser auch:

List(3,7,5,2).sorted

Hendrik
quelle
Und ich nehme an, umgekehrt zu sortieren, ist der idiomatische Weg List(3,7,5,2).sorted.reverse?
Nick Chammas
19

Wenn Sie nur Dinge sortieren möchten, aber nicht speziell mit dem Sortierobjekt verheiratet sind, können Sie die Sortiermethode von List verwenden. Es wird eine Vergleichsfunktion als Argument verwendet, sodass Sie sie für alle gewünschten Typen verwenden können:

List("Steve", "Tom", "John", "Bob").sort((e1, e2) => (e1 compareTo e2) < 0)

List(1, 4, 3, 2).sort((e1, e2) => (e1 < e2))

Listen gelten wahrscheinlich als "schuppiger" als Arrays.

Aus den Scala-API- Dokumenten :

def sort (lt: (A, A) => Boolean): Liste [A]

Sort the list according to the comparison function <(e1: a, e2: a) =>

Boolescher Wert, der wahr sein sollte, wenn e1 kleiner als e2 ist.

Peter Recore
quelle
Hmm, List hat also eine Sortiermethode, Array jedoch nicht. Wie unbefriedigend unregelmäßig. Ich erwarte diese Art von Unsinn von der Java-API, aber nicht von Scala.
Skaffman
Ich bin zu sehr ein Scala-Neuling, um es sicher zu wissen, aber es kann ein notwendiges Übel sein, da Scala die Kompatibilität mit all dem Java-Zeug beibehält. Auf der anderen Seite macht Scala so viel Magie, dass es normal genug erscheint, um noch mehr zu wollen!
Peter Recore
5
List (...) sort {_ <_} wäre idiomatischer.
Daniel Spiewak
2
Es ist auch erwähnenswert, dass String (durch eine implizite Konvertierung) die <Methode: "daniel" <"chris" == false definiert
Daniel Spiewak
11
Nur zur Information, auf Scala 2.9.1 Sort scheint veraltet zu sein, verwenden Sie sortWith
Jérôme
5
val array = Array((for(i <- 0 to 10) yield scala.util.Random.nextInt): _*)
scala.util.Sorting.quickSort(array)

Das "Standard" -Array von Scala ist eine veränderbare Datenstruktur, die dem Array von Java sehr nahe kommt. Im Allgemeinen bedeutet dies, dass ein "Array" nicht sehr skaliert ist, selbst wenn veränderbare Datenstrukturen vorhanden sind. Es erfüllt jedoch einen Zweck. Wenn das Array der richtige Datentyp für Ihre Anforderungen ist, sortieren Sie es so. Es gibt übrigens andere Sortiermethoden für die Objektsortierung.

Ich glaube, ich habe gerade begriffen, was Ihre Frage ist ... Sie müssen keinen impliziten Parameter übergeben (es ist schließlich implizit). Dieser Parameter besagt, dass es eine Möglichkeit geben muss, den Typ K in einen geordneten [K] umzuwandeln. Diese Definitionen existieren bereits für Scalas Klassen, sodass Sie sie nicht benötigen.

Für eine beliebige Klasse können Sie dies folgendermaßen definieren:

scala> case class Person(name: String)
defined class Person

scala> val array = Array(Person("John"), Person("Mike"), Person("Abe"))
array: Array[Person] = Array(Person(John), Person(Mike), Person(Abe))

scala> scala.util.Sorting.quickSort(array)
<console>:11: error: no implicit argument matching parameter type (Person) => Ordered[Person] was found.
       scala.util.Sorting.quickSort(array)
                                   ^
scala> class OrderedPerson(val person: Person) extends Ordered[Person] {
     | def compare(that: Person) = person.name.compare(that.name)
     | }
defined class OrderedPerson

scala> implicit def personToOrdered(p: Person) = new OrderedPerson(p)
personToOrdered: (p: Person)OrderedPerson

scala> scala.util.Sorting.quickSort(array)

scala> array
res8: Array[Person] = Array(Person(Abe), Person(John), Person(Mike))

Wenn Person von Anfang an befohlen worden wäre, wäre dies kein Problem:

scala> case class Person(name: String) extends Ordered[Person] {
     | def compare(that: Person) = name.compare(that.name)
     | }
defined class Person

scala> val array = Array(Person("John"), Person("Mike"), Person("Abe"))
array: Array[Person] = Array(Person(John), Person(Mike), Person(Abe))

scala>  scala.util.Sorting.quickSort(array)

scala> array
res10: Array[Person] = Array(Person(Abe), Person(John), Person(Mike))
Daniel C. Sobral
quelle
Entschuldigung, mir war nicht klar: Ich muss eine Reihe von Objekten beliebigen Typs sortieren, keine Zahlen.
Dan Gravell
3

Während die akzeptierte Antwort nicht falsch ist, bietet die Quicksort-Methode mehr Flexibilität. Ich habe dieses Beispiel für Sie geschrieben.

import System.out.println
import scala.util.Sorting.quickSort

class Foo(x:Int) {
def get = x
}

//a wrapper around Foo that implements Ordered[Foo]
class OrdFoo(x:Foo) extends Ordered[Foo] {
def compare(that:Foo) = x.get-that.get
}
//another wrapper around Foo that implements Ordered[Foo] in a different way
class OrdFoo2(x:Foo) extends Ordered[Foo] {
def compare(that:Foo) = that.get-x.get
}
//an implicit conversion from Foo to OrdFoo
implicit def convert(a:Foo) = new OrdFoo(a)

//an array of Foos
val arr = Array(new Foo(2),new Foo(3),new Foo(1))

//sorting using OrdFoo
scala.util.Sorting.quickSort(arr)
arr foreach (a=>println(a.get))
/*
This will print:
1
2
3
*/

//sorting using OrdFoo2
scala.util.Sorting.quickSort(arr)(new OrdFoo2(_))
arr foreach (a=>println(a.get))
/*
This will print:
3
2
1
*/

Dies zeigt, wie implizite und explizite Konvertierungen von Foo in eine Klasse, die Ordered [Foo] erweitert, verwendet werden können, um verschiedene Sortierreihenfolgen zu erhalten.

Kim Stebel
quelle
2

Ich bevorzuge die Benutzersortierung util

Beispiel:

val arr = Array(7,5,1, 9,2)

scala.util.Sorting.quickSort(arr)

Bitte lesen Sie diese für weitere Informationen Sorting util

Ahmad Al-Kurdi
quelle
Warum ein Link zu den alten 2.9.0-API-Dokumenten anstelle der aktuellen Dokumente ?
Jwvh