¿Cómo clasifico una matriz en Scala?


80

Puedo ver que hay un objeto de clasificación Sorting, con un método de clasificación rápidaquickSort , en él.

¿Cuál sería un ejemplo de código de su uso, ordenando una matriz de objeto de tipo arbitrario? Parece que necesito pasar una implementación del Orderablerasgo, pero no estoy seguro de la sintaxis.

Además, preferiría respuestas haciendo esto a la 'manera Scala'. Sé que puedo usar una biblioteca de Java.

Respuestas:


32

Sorting.quickSort declara funciones para tomar una matriz de números o cadenas, pero supongo que quiere decir que desea ordenar una lista de objetos de sus propias clases.

La función que creo que estás viendo es

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

Lo cual, si estoy leyendo esto correctamente, significa que los objetos en la matriz deben tener el Orderedrasgo. Entonces, su clase debe extenderse Ordered(o debe mezclarla) y, por lo tanto, debe implementar el comparemétodo de ese rasgo.

Entonces, para copiar un ejemplo del libro:

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

Entonces, dado un Array [MyClass], entonces Sorting.quickSort debería funcionar.


Sí, ese es el indicado. Tiene sentido ahora que lo señala. ¿Cómo lo 'mezclaría'?
Dan Gravell

Ver editar. O extiende como mi ejemplo, o usa "class MyClass extiende OtherClass con Ordered [MyClass]", que es una mezcla.
skaffman

Gracias. Creo que haré lo último.
Dan Gravell

6
No quiero ser pedante, pero ... su clase no necesita extender Ordered, es suficiente que haya una vista (también conocida como conversión implícita) en el alcance de su clase a algo que sí extienda Ordered.
Kim Stebel

99

Con Scala 2.8 o posterior es posible hacer:

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

que usa java.util.Arrays.sort , una implementación de quicksort.


2
Usando el orden implícito, incluso más corto: List (3,7,5,2) .sorted según scala.collection.immutable.LinearSeq
Utgarda

¿Cómo sabemos que sortWith está usando java.util.Arrays.sort? ¿Hay alguna referencia para eso?
deepkimo


Esto es un poco diferente de lo que estaba haciendo la pregunta original. Ciertamente funciona para crear una nueva Lista ordenada (o Matriz como se planteó en la pregunta original) pero sortWith devuelve un nuevo objeto en lugar de ordenar la Lista o Matriz original en su lugar.
rphutchinson

57

Hoy en día este también funciona:

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


Y supongo que para ordenar al revés, ¿la forma idiomática es List(3,7,5,2).sorted.reverse?
Nick Chammas

19

Si solo desea ordenar cosas, pero no está casado con el objeto de clasificación en particular, puede usar el método de clasificación de Lista. Toma una función de comparación como argumento, por lo que puede usarla en los tipos que desee:

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

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

Las listas probablemente califiquen como "más escalables" que las matrices.

De los documentos de la API de Scala :

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

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

Booleano, que debería ser verdadero si e1 es menor que e2.


Hmm, entonces List tiene un método de ordenación, pero Array no. Qué insatisfactoriamente irregular. Espero ese tipo de tonterías de la API de Java, pero no de Scala.
skaffman

Soy demasiado novato en Scala como para saberlo con certeza, pero puede ser un mal necesario, dado que Scala mantiene la compatibilidad con todas las cosas de Java. Por otro lado, Scala hace tanta magia, ¡parece lo suficientemente normal como para querer que haga aún más!
Peter Recore

5
List (...) sort {_ <_} sería más idiomático.
Daniel Spiewak

2
También vale la pena señalar que String define (a través de una conversión implícita) el <método: "daniel" <"chris" == false
Daniel Spiewak

11
Solo para obtener información, en scala 2.9.1 sort parece obsoleto, use sortWith
Jérôme

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

La matriz "predeterminada" de Scala es una estructura de datos mutable, muy cercana a la matriz de Java. En términos generales, eso significa que una "matriz" no es muy Scala-ish, incluso cuando las estructuras de datos mutables funcionan. Sin embargo, tiene un propósito. Si la matriz es el tipo de datos correcto para sus necesidades, así es como lo clasifica. Hay otros métodos de clasificación en la clasificación de objetos, por cierto.

Creo que me acabo de dar cuenta de cuál es tu pregunta ... no necesitas pasar ningún parámetro implícito (es implícito, después de todo). Ese parámetro existe para decir que debe haber alguna forma de convertir el tipo K en un Ordered [K]. Estas definiciones ya existen para las clases de Scala, por lo que no las necesita.

Para una clase arbitraria, puede definirla de esta manera:

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

Ahora, si la Persona fue ordenada para empezar, esto no sería un problema:

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

Disculpas, no estaba claro: necesito ordenar una serie de objetos de tipo arbitrario, no números.
Dan Gravell

3

Si bien la respuesta aceptada no es incorrecta, el método de ordenación rápida proporciona más flexibilidad que eso. Escribí este ejemplo para ti.

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

Esto muestra cómo las conversiones implícitas y explícitas de Foo a alguna clase que extiende Ordered [Foo] pueden usarse para obtener diferentes órdenes de clasificación.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.