web-dev-qa-db-fra.com

Comment trier un tableau dans Scala?

Je peux voir qu'il y a un objet de tri, Sorting, avec une méthode quicksort , quickSort, dessus.

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

De plus, je préférerais que les réponses le fassent de la manière Scala. Je sais que je peux simplement utiliser une bibliothèque Java.

80
Dan Gravell

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

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

Donc, pour arracher un exemple du livre:

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

Donc, étant donné un tableau [MyClass], alors Sorting.quickSort devrait fonctionner.

32
skaffman

Avec Scala 2.8 ou supérieur, il est possible de faire:

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

qui utilise Java.util.Arrays.sort , une implémentation de quicksort.

98
adelarsq

De nos jours, celui-ci fonctionne aussi:

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

54
hendrik

Si vous voulez simplement trier des choses, mais que vous n'êtes pas marié à l'objet de tri en particulier, vous pouvez utiliser la méthode de tri de List. Il prend une fonction de comparaison comme argument, vous pouvez donc l'utiliser sur tous les types 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))

Les listes sont probablement qualifiées de "plus scalaires" que les tableaux.

Depuis le scala api docs :

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

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

Booléen, qui devrait être vrai si e1 est plus petit que e2.

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

Le tableau "par défaut" de Scala est une structure de données mutable, très proche du tableau de Java. D'une manière générale, cela signifie qu'un "tableau" n'est pas très Scala-ish, même si les structures de données mutables disparaissent. Mais cela sert un but. Si le tableau est le type de données adapté à vos besoins, c'est ainsi que vous le triez. Soit dit en passant, il existe d'autres méthodes de tri sur le tri d'objets.

Je pense que je viens de réaliser quelle est votre question ... vous n'avez pas besoin de passer de 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 ordonné [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 la définir de cette façon:

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 reçu l'ordre de 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))
5
Daniel C. Sobral

Bien que la réponse acceptée ne soit pas fausse, la méthode de tri rapide 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 vers une classe étendant Ordered [Foo] peuvent être utilisées pour obtenir différents ordres de tri.

3
Kim Stebel

Je préfère l'utilisateur Util de tri

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 til de tri

2
Ahmad Al-Kurdi