2009-07-15 7 views
71

Je vois qu'il y a un objet de tri, Sorting, avec une méthode quicksort, quickSort, dessus.Comment trier un tableau dans Scala?

Quel serait un exemple de code de l'utiliser, en triant un tableau d'objet de type arbitraire? Il semble que je doive passer dans une implémentation du trait Orderable, mais je ne suis pas sûr de la syntaxe.

En outre, je préférerais que l'on réponde à la «méthode Scala». Je sais que je peux juste utiliser une bibliothèque Java.

Répondre

27

Sorting.quickSort déclare des fonctions pour prendre un tableau de nombres ou de chaînes, mais je suppose que vous voulez dire que vous voulez trier une liste d'objets de vos propres classes?

La fonction que je pense que vous regardez est

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

qui, si je lis ce droit, signifie que les objets du tableau doivent avoir le trait Ordered. Donc, votre classe doit étendre Ordered (ou doit le mélanger), et doit donc implémenter la méthode compare de ce trait.

Donc, pour arnaquer un exemple du livre:

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

donc donné un tableau [MyClass], puis Sorting.quickSort devrait fonctionner.

+0

Oui, c'est celui-là. C'est logique maintenant que vous le signalez. Comment pourrais-je le mélanger? –

+0

Voir édition. Vous pouvez * étendre * comme mon exemple, ou utiliser "class MyClass extends OtherClass avec Ordered [MyClass]", qui est un mix-in. – skaffman

+0

Merci. Je pense que je ferai le dernier. –

4
val array = Array((for(i <- 0 to 10) yield scala.util.Random.nextInt): _*) 
scala.util.Sorting.quickSort(array) 

La matrice "par défaut" de Scala est une structure de données mutable, très proche de celle de Java. En règle générale, cela signifie qu'un "tableau" n'est pas très Scala-ish, même si les structures de données mutables vont. Cela sert un but, cependant. Si le tableau est le bon type de données pour votre besoin, alors c'est comme ça que vous le faites. Il y a d'autres méthodes de tri sur le tri des objets, d'ailleurs.

Je pense que je viens de réaliser quelle est votre question ... vous n'avez besoin de passer aucun paramètre implicite (c'est implicite, après tout). Ce paramètre existe pour dire qu'il doit y avoir un moyen de convertir le type K en un Ordered [K]. Ces définitions existent déjà pour les classes de Scala, donc vous n'en avez pas besoin.

Pour une classe arbitraire, vous pouvez le définir ainsi:

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

Maintenant, si la personne a été condamnée à commencer, ce ne serait pas un problème:

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

Excuses, je n'étais pas clair: j'ai besoin de trier un tableau d'objets de type arbitraire, pas de nombres. –

19

Si vous souhaitez simplement trier les éléments, mais que vous n'êtes pas particulièrement marié à l'objet Tri, vous pouvez utiliser la méthode de tri de List. Il faut une fonction de comparaison comme argument, vous pouvez l'utiliser sur tout type que vous souhaitez:

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

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

Listes probablement devenue « plus scalaish » que les tableaux.

De l'api scala docs:

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

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

Boolean, qui devrait être vrai ssi e1 est plus petit que e2.

+0

Hmm, donc List a une méthode de tri, mais Array ne le fait pas. Comme insatisfaisant irrégulier. J'attends ce genre de non-sens de l'API Java, mais pas de Scala. – skaffman

+0

Je suis trop scala newb pour être sûr, mais c'est peut-être un mal nécessaire, étant donné que Scala maintient la compatibilité avec tous les trucs java. D'un autre côté, Scala fait tellement de magie, il semble normal de vouloir en faire encore plus! –

+5

Liste (...) sort {_ <_} serait plus idiomatique. –

3

Bien que la réponse acceptée ne soit pas fausse, la méthode quicksort offre plus de flexibilité que cela. J'ai écrit cet exemple pour vous.

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 
*/ 

Cela montre comment les conversions implicites et explicites de Foo à une classe étendue Ordonné [Foo] peut être utilisé pour obtenir différents ordres de tri.

91

Avec Scala 2.8 ou plus tard, il est possible de le faire:

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

qui utilise java.util.Arrays.sort, une mise en œuvre de quicksort.

+2

Utilisant la commande implicite, encore plus court: List (3,7,5,2) .sorted selon [scala.collection.immutable.LinearSeq] (http://www.scala-lang.org/api/current/index.html#scala. collection.immutable.LinearSeq) – Utgarda

+0

Comment savons-nous que sortWith utilise java.util.Arrays.sort? Y a-t-il une référence pour cela? – deepkimo

+0

@deepkimo dans le code source https://github.com/scala/scala/blob/2.12.x/src/library/scala/collection/SeqLike.scala#L618 – adelarsq

42

Aujourd'hui celui-ci fonctionne aussi:

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

1

Je préfère à l'utilisateur Tri util

Exemple:

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

scala.util.Sorting.quickSort(arr) 

s'il vous plaît lire ceci pour plus d'informations Sorting util

+0

Pourquoi un lien vers les anciens docs de l'API 2.9.0 au lieu des [documents actuels] (http://www.scala-lang.org/api/current/scala/util/Sorting$.html)? – jwvh

+0

Fait, merci beaucoup –

Questions connexes