Làm cách nào để sắp xếp một mảng trong Scala?


80

Tôi có thể thấy có một đối tượng sắp xếp Sorting, với phương pháp quicksortquickSort , trên đó.

Một ví dụ mã nào về việc sử dụng nó, sắp xếp một mảng đối tượng có kiểu tùy ý? Có vẻ như tôi cần chuyển một cách triển khai Orderableđặc điểm, nhưng tôi không chắc về cú pháp.

Ngoài ra, tôi muốn các câu trả lời làm điều này theo 'cách Scala'. Tôi biết tôi chỉ có thể sử dụng một thư viện Java.

Câu trả lời:


32

Sorting.quickSort khai báo các hàm để lấy Mảng số hoặc Chuỗi, nhưng tôi giả sử ý bạn là bạn muốn sắp xếp một danh sách các đối tượng thuộc các lớp của riêng bạn?

Chức năng mà tôi nghĩ bạn đang xem là

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

Điều này, nếu tôi đang đọc đúng, có nghĩa là các đối tượng trong Mảng phải có Orderedđặc điểm. Vì vậy, lớp của bạn phải mở rộng Ordered(hoặc phải trộn nó vào), và do đó phải triển khai comparephương thức của đặc điểm đó.

Vì vậy, để trích xuất một ví dụ từ cuốn sách:

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

Vì vậy, được cung cấp một Mảng [MyClass], thì Sorting.quickSort sẽ hoạt động.


Vâng, đó là một trong những. Bây giờ bạn chỉ ra nó có ý nghĩa. Tôi sẽ 'trộn nó vào' như thế nào?
Dan Gravell,

Xem chỉnh sửa. Bạn có thể mở rộng như ví dụ của tôi hoặc sử dụng "lớp MyClass mở rộng OtherClass với [MyClass] có thứ tự", là một kết hợp.
skaffman

Cảm ơn. Tôi nghĩ tôi sẽ làm phần sau.
Dan Gravell

6
Không phải là phức tạp, nhưng ... lớp của bạn không cần phải mở rộng Đã đặt hàng, chỉ cần có một chế độ xem (còn được gọi là chuyển đổi ngầm định) trong phạm vi từ lớp của bạn sang một thứ gì đó mở rộng Có Thứ tự.
Kim Stebel

99

Với Scala 2.8 trở lên, bạn có thể thực hiện:

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

sử dụng java.util.Arrays.sort , một triển khai của quicksort.


2
Sử dụng thứ tự ngầm, thậm chí ngắn hơn: Danh sách (3,7,5,2) .sorted theo scala.collection.immutable.LinearSeq
Utgarda

Làm cách nào để biết sortWith đang sử dụng java.util.Arrays.sort? Có một tài liệu tham khảo cho điều đó?
deepkimo


Điều này hơi khác một chút so với những gì câu hỏi ban đầu đã hỏi. Nó chắc chắn hoạt động để tạo một Danh sách được sắp xếp mới (hoặc Mảng như được đặt ra trong câu hỏi ban đầu) nhưng sortWith trả về một đối tượng mới trái ngược với việc sắp xếp Danh sách hoặc Mảng ban đầu tại chỗ.
rphutchinson

57

Ngày nay cái này cũng hoạt động:

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


Và tôi cho rằng sắp xếp ngược lại, cách thành ngữ là List(3,7,5,2).sorted.reverse?
Nick Chammas

19

Nếu bạn chỉ muốn sắp xếp mọi thứ, nhưng không kết hợp cụ thể với đối tượng Sắp xếp, bạn có thể sử dụng phương pháp sắp xếp của Danh sách. Nó sử dụng một hàm so sánh làm đối số, vì vậy bạn có thể sử dụng nó trên bất kỳ kiểu nào bạn muốn:

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

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

Danh sách có thể đủ điều kiện là "nhiều quy mô hơn" so với mảng.

Từ tài liệu api scala :

def sort (lt: (A, A) => Boolean): Danh sách [A]

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

Boolean, phải là true iff e1 nhỏ hơn e2.


Hmm, vậy là List có một phương thức sắp xếp, nhưng Array thì không. Làm thế nào không hài lòng bất thường. Tôi mong đợi điều vô nghĩa đó từ Java API, nhưng không phải Scala.
skaffman

Tôi quá là một người mới có vảy để biết chắc chắn, nhưng nó có thể là một điều xấu cần thiết, vì Scala đang duy trì khả năng tương thích với tất cả các nội dung java. Mặt khác, Scala làm được quá nhiều ma thuật, có vẻ bình thường đến mức muốn nó làm được nhiều hơn thế!
Peter Recore vào

5
Danh sách (...) sắp xếp {_ <_} sẽ mang tính thành ngữ hơn.
Daniel Spiewak,

2
Nó cũng đáng chú ý là chuỗi không xác định (thông qua một chuyển đổi ngầm) các <phương pháp: "daniel" < "chris" == false
Daniel Spiewak

11
Chỉ để biết, trên scala 2.9.1 loại dường như bị phản đối, sử dụng sortWith
Jérôme

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

Mảng "mặc định" của Scala là một cấu trúc dữ liệu có thể thay đổi, rất gần với Mảng của Java. Nói chung, điều đó có nghĩa là một "mảng" không phải là Scala-ish, ngay cả khi cấu trúc dữ liệu có thể thay đổi được. Tuy nhiên, nó phục vụ một mục đích. Nếu mảng là kiểu dữ liệu phù hợp với nhu cầu của bạn, thì đó là cách bạn sắp xếp nó. Nhân tiện, có các phương pháp sắp xếp khác về Sắp xếp đối tượng.

Tôi nghĩ rằng tôi vừa nhận ra câu hỏi của bạn là gì ... bạn không cần phải truyền bất kỳ tham số ngầm nào (suy cho cùng thì nó cũng ngầm hiểu). Tham số đó tồn tại để nói rằng phải có một số cách để chuyển loại K thành một [K] có thứ tự. Các định nghĩa này đã tồn tại cho các lớp của Scala, vì vậy bạn không cần chúng.

Đối với một lớp tùy ý, bạn có thể định nghĩa nó theo cách này:

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

Bây giờ, nếu Người được Thứ tự bắt đầu, thì điều này sẽ không thành vấn đề:

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

Xin lỗi, tôi không rõ ràng: Tôi cần sắp xếp một mảng các đối tượng thuộc loại tùy ý, không phải số.
Dan Gravell,

3

Mặc dù câu trả lời được chấp nhận không sai, nhưng phương pháp nhanh chóng cung cấp tính linh hoạt hơn thế. Tôi đã viết ví dụ này cho bạn.

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

Điều này cho thấy cách chuyển đổi ngầm và rõ ràng từ Foo sang một số lớp mở rộng [Foo] có thứ tự có thể được sử dụng để nhận các thứ tự sắp xếp khác nhau.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.