如何在Scala中对数组排序?


80

我可以看到上面有一个Sorting带有快速排序方法的排序对象quickSort

使用它对任意类型的对象数组进行排序的代码示例是什么?看起来我需要传递Orderabletrait的实现,但是我不确定语法。

另外,我希望以“ Scala方式”进行回答。我知道我只能使用Java库。

Answers:


32

Sorting.quickSort声明用于获取数字或字符串数​​组的函数,但是我假设您的意思是要对自己类的对象列表进行排序?

我认为您正在查看的功能是

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

如果我没看错,这意味着Array中的对象必须具有Ordered特征。因此,您的类必须扩展Ordered(或必须将其混合),因此必须实现该compare特征的方法。

因此,从书中摘录一个例子:

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

因此,给定一个Array [MyClass],则Sorting.quickSort应该可以工作。


是的,就是那个。现在您指出来就很有意义。我将如何“混入”?
Dan Gravell

参见编辑。您可以像我的示例一样扩展,也可以使用“ Class MyClass用Ordered [MyClass]扩展OtherClass”,这是一种混合。
skaffman

谢谢。我想我会去做。
丹·格雷弗

6
不必太花哨,但是...您的类无需扩展Ordered,就可以从您的类到一个确实扩展了Ordered的范围的视图(也称为隐式转换)就足够了。
Kim Stebel,2010年

99

使用Scala 2.8或更高版本,可以执行以下操作:

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

使用java.util.Arrays.sort(快速排序的实现)。


2
使用隐式排序,甚至更短:List(3,7,5,2)。按scala.collection.immutable.LinearSeq
排序

我们如何知道sortWith正在使用java.util.Arrays.sort?有参考吗?
deepkimo 2014年

源代码中的@deepkimogithub.com
scala/

这与最初的问题有所不同。它当然可以创建一个新的排序列表(或原始问题中的数组),但是sortWith返回一个新对象,而不是对原始列表或数组进行适当排序。
rphutchinson 2014年

57

如今,这一功能也适用:

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


我想反过来说,惯用的方式是List(3,7,5,2).sorted.reverse
Nick Chammas

19

如果您只想对事物进行排序,但又不特别喜欢Sorting对象,则可以使用List的sort方法。它以比较函数作为参数,因此您可以在所需的任何类型上使用它:

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

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

列表可能比数组更有资格。

从scala api文档

def sort(lt:(A,A)=>布尔值):列表[A]

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

布尔值,当e1小于e2时应为true。


嗯,所以List有一个排序方法,而Array没有。多么令人不满的不规则。我希望Java API会提供这种废话,但Scala不会。
skaffman

我实在不知道一个太多的scala newb,但是鉴于Scala保持与所有Java东西的兼容性,这可能是一个必要的邪恶。另一方面,Scala发挥了很大的魔力,似乎足以让它做更多的事情了!
Peter Recore 09年

5
List(...)排序{_ <_}会更惯用。
Daniel Spiewak

2
还值得注意的是,String确实(通过隐式转换)定义了<方法:“ daniel” <“ chris” == false
Daniel Spiewak 09年

11
只是为了信息,斯卡拉2.9.1排序似乎过时了,用sortWith
杰罗姆

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

Scala的“默认”数组是一种可变的数据结构,非常类似于Java的Array。一般而言,这意味着“数组”不是十分可伸缩的,即使可变数据结构也是如此。不过,这是有目的的。如果array是满足您需要的正确数据类型,那么这就是对它进行排序的方式。顺便说一下,还有其他关于对象排序的排序方法。

我想我刚刚意识到您的问题是什么...您不需要传递任何隐式参数(毕竟它是隐式的)。该参数的存在表明必须有某种方法将类型K转换为Ordered [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))

抱歉,我不清楚:我需要对任意类型而不是数字的对象数组进行排序。
丹·格雷夫

3

尽管公认的答案没有错,但是quicksort方法提供了更大的灵活性。我为您编写了此示例。

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隐式和显式转换到扩展Ordered [Foo]的某个类,以获取不同的排序顺序。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.