Як відсортувати масив у Scala?


81

Я бачу, що на ньому є об’єкт сортування Sortingз методом швидкої сортування quickSort.

Що може бути прикладом коду його використання, сортування масиву об'єкта довільного типу? Схоже, мені потрібно передати реалізацію Orderableознаки, але я не впевнений у синтаксисі.

Крім того, я б віддав перевагу відповіді, які роблять це за "шкалою". Я знаю, що можу просто користуватися бібліотекою Java.

Відповіді:


32

Sorting.quickSort оголошує функції для прийняття масиву чисел або рядків, але я припускаю, що ви маєте на увазі, що хочете відсортувати список об'єктів власних класів?

Я вважаю, що функція, яку ви розглядаєте

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

Що, якщо я правильно це читаю, означає, що об’єкти в масиві повинні мати Orderedознаку. Отже, ваш клас повинен розширювати Ordered(або повинен змішувати його), а отже, повинен застосовувати compareметод цієї ознаки.

Отже, щоб вирвати приклад із книги:

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

Отже, якщо задано масив [MyClass], тоді Sorting.quickSort має працювати.


Так, це той. Це має сенс, коли ви на це вказуєте. Як би я змішав це?
Ден Гравелл,

Дивіться редагування. Ви або розширюєте, як мій приклад, або використовуєте "клас MyClass розширює OtherClass з упорядкованим [MyClass]", який є сумішшю.
skaffman

Дякую. Думаю, зроблю останнє.
Dan Gravell,

6
Щоб не бути педантичним, але ... ваш клас не повинен розширювати порядок, достатньо, щоб у вашому класі був вигляд (також відомий як неявне перетворення) на те, що дійсно поширюється впорядковано.
Кім Стебель

100

За допомогою Scala 2.8 або пізнішої версії можна зробити:

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

що використовує java.util.Arrays.sort , реалізацію швидкого сортування.


2
Використовуючи неявне впорядкування, ще коротше: List (3,7,5,2). Сортується за scala.collection.immutable.LinearSeq
Utgarda

Звідки ми знаємо, що sortWith використовує java.util.Arrays.sort? Чи є посилання на це?
deepkimo


Це дещо інше, ніж те, що задавалось оригінальним запитанням. Це, безумовно, працює для створення нового відсортованого списку (або масиву, як зазначено у вихідному питанні), але sortWith повертає новий об'єкт на відміну від сортування оригінального списку або масиву на місці.
rphutchinson


19

Якщо ви просто хочете відсортувати речі, але, зокрема, не одружені з об’єктом Сортування, ви можете скористатися методом сортування List. В якості аргументу вона приймає функцію порівняння, тому ви можете використовувати її для будь-яких типів, які хочете:

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

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

Списки, ймовірно, кваліфікуються як "більш масштабні", ніж масиви.

З Scala API Docs :

def sort (lt: (A, A) => Boolean): Список [A]

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

Логічне значення, яке має бути істинним, якщо e1 менше, ніж e2.


Хм, отже, List має метод сортування, але Array - ні. Як невдоволено нерегулярно. Я чекаю подібних дурниць від Java API, але не від Scala.
skaffman

Я занадто багато новачків Scala, щоб точно знати, але це може бути необхідним злом, враховуючи те, що Scala підтримує сумісність з усіма матеріалами Java. З іншого боку, Скала робить стільки магії, що здається досить нормальним, щоб хотілося, щоб це робило ще більше!
Peter Recore

5
Сортування списку (...) {_ <_} було б більш ідіоматичним.
Даніель Співак

2
Варто також зазначити, що String визначає (шляхом неявного перетворення) метод <:: daniel »<" chris "== false
Даніель Співак

11
Тільки для інформації, у Scala 2.9.1 сортування видається застарілим, використовуйте sortWith
Jérôme

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

Масив "за замовчуванням" Scala - це змінна структура даних, дуже близька до масиву Java. Взагалі кажучи, це означає, що "масив" не дуже масштабований, навіть якщо змінюються структури даних. Однак це має мету. Якщо масив є правильним типом даних для ваших потреб, то саме таким чином ви його сортуєте. До речі, існують й інші методи сортування об’єкту Сортування.

Здається, я щойно зрозумів, у чому ваше питання ... вам не потрібно передавати жоден неявний параметр (зрештою, це неявний). Цей параметр існує, щоб сказати, що має бути певний спосіб перетворити тип K в упорядкований [K]. Ці визначення вже існують для класів Scala, тому вони вам не потрібні.

Для довільного класу ви можете визначити це таким чином:

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

Тепер, якби для початку було наказано Person, це не склало б проблем:

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

Перепрошую, я не зрозумів: мені потрібно відсортувати масив об’єктів довільного типу, а не цифр.
Dan Gravell,

3

Хоча прийнята відповідь не є неправильною, метод швидкого сортування забезпечує більшу гнучкість, ніж це. Я написав цей приклад для вас.

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

Це показує, як неявні та явні перетворення з Foo в якийсь клас, що розширюється впорядкований [Foo], можуть бути використані для отримання різних порядків сортування.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.