2015-07-26 24 views
5

Tôi muốn sắp xếp một mảng của các bộ bởi thứ 3 và phần tử đầu tiên vì vậy tôi sử dụng đoạn mã sau:Sử dụng lệnh để sắp xếp mảng của mảng, tăng dần và giảm dần

import scala.util.Sorting 
val pairs = Array(("a", 5, 2), ("c", 3, 1), ("b", 1, 3)) 

// sort by the 3rd element, then 1st 
Sorting.quickSort(pairs)(Ordering[(Int, String)].on(x => (x._3, x._1))) 

Câu hỏi của tôi là, trong ví dụ trước tôi có thể sắp xếp theo cả phần tử thứ ba và thứ nhất tăng dần hoặc cả hai phần tử giảm dần (sử dụng ngược lại). nhưng cách sắp xếp theo phần tử thứ ba tăng dần và phần tử thứ nhất giảm dần.

Xin vui lòng, trong câu trả lời của bạn xem xét các trường hợp sau đây:

Array[Array[People]] 

nơi trong trường hợp này tôi không biết kích thước chính xác của các mảng nội (phụ thuộc vào giản đồ tập tin mà tôi đọc vào mảng này) và Tôi muốn sắp xếp theo tất cả các mục trong một bên (một số tăng dần và một số giảm dần).

Chỉnh sửa: Có vẻ như, tôi đã bỏ lỡ hiểu.

Đây là trường hợp đầy đủ của tôi: Tôi có các lớp sau:

sealed trait GValue extends Serializable with Ordered[GValue]{ 
def compare(o: GValue): Int = { 
    o match { 
    case GDouble(v) => this.asInstanceOf[GDouble].v compare v 
    case GString(v) => this.asInstanceOf[GString].v compare v 
    } 
} 

case class GDouble(v: Double) extends GValue 

case class GString(v: String) extends GValue 

và tôi muốn làm một mã như thế này.

// (startInterval, StopInterval, ArrayOfColumns) 
    val intervals: Array[(Long,Long,Array[GValue])] = 
Array((10,20,Array(GDouble(10.2), GString("alarm"), GString("error"),GDouble("100.234"))), 
    (30,2000,Array(GDouble(-10.2), GString("alarm"), GString("warn"),GDouble("0.234")))) 

Giản đồ hoặc mảng bên trong sẽ thay đổi dựa trên tệp đầu vào (trong ví dụ là Double, String, String, Double nhưng có thể là Double, Double hoặc cái gì khác). Tôi muốn tìm một cách để sắp xếp với bao gồm tất cả các trường hợp của mảng bên trong (liên quan đến loại và độ dài), tăng dần và giảm dần.

những gì tôi làm hiện tại là thay đổi mảng bên trong thành Iterable và sau đó sử dụng Ordering [Iterable [GValue]] để sắp xếp hoặc Sắp xếp [Iterable [GValue]]. Nhưng tôi muốn sắp xếp theo các hướng tách ra (tăng dần cho cột đầu tiên và sau đó giảm dần cho phần thứ hai sau đó tăng dần đến thứ ba và vân vân)

+0

Bạn muốn sắp xếp các 'mảng intervals' dựa trên một số yếu tố của 'Array [GValue]'? –

+0

@Peter Neyens, Có, Bạn hoàn toàn đúng :) – Abdulrahman

Trả lời

3

Sử dụng Régis Jean-Gilles' CompositeOrdering from another question, chúng tôi có thể soạn nhiều Orderings.

// Ordering to sort an Array[GValue] by column "col" 
def orderByColumn(col: Int) = Ordering.by { ar: Array[GValue] => ar(col - 1) } 

val `By Col3-Desc/Col1` = 
    CompositeOrdering(orderByColumn(3).reverse, orderByColumn(1)) 

val `By Col1/Col2/Col3` = 
    CompositeOrdering(orderByColumn(1), orderByColumn(2), orderByColumn(3)) 

Bây giờ chúng ta có thể sắp xếp một mảng kiểu Array[GValue], và bạn có thể sắp xếp intervals bạn sử dụng sortBy:

intervals.sortBy(_._3)(`By Col3-Desc/Col1`) 

Nếu bạn muốn sắp xếp mảng intervals với Sorting.quickSort, chúng ta cần một Ordering cho tuple:

type Interval = (Long, Long, Array[GValue]) 
implicit object tupleByArray extends Ordering[Interval] { 
    def compare(a: Interval, b: Interval) = a._3 compare b._3 
} 

Bây giờ bạn có thể sắp xếp intervals bằng cách sử dụng Sorting.quickSort:

implicit val arrOrd = `By Col3-Desc/Col1` 
Sorting.quickSort(intervals) 

// Array[(Long, Long, Array[GValue])] = 
// Array(
// (30,2000,Array(GDouble(-10.2), GString(alarm), GString(warn), GDouble(0.234))), 
// (10,20,Array(GDouble(10.2), GString(alarm), GString(error), GDouble(100.234))) 
//) 

tôi để lại câu trả lời của tôi từ trước khi câu hỏi được cập nhật:

Có một great article by Eric Loots trên sắp xếp trên nhiều lĩnh vực.

Trong trường hợp của bạn của Array[People] này có thể trông giống như:

case class People(name: String, age: Int) 

object PeopleOrdering { 
    // sort by name descending and age ascending 
    implicit object `By Name-Rev/Age` extends Ordering[People] { 
    def compare(a: People, b: People): Int = { 
     import scala.math.Ordered._ 
     implicit val ord = Ordering.Tuple2[String, Int] 
     (b.name, a.age) compare (a.name, b.age) 
    } 
    } 
} 

val people = Array(People("Alice", 40), People("Bob", 50), People("Charlie", 20)) 
Sorting.quickSort(people)(PeopleOrdering.`By Name-Rev/Age`) 
// > people 
// Array[People] = Array(People(Bob,20), People(Bob,50), People(Alice,40)) 

val array = Array(people, Array(People("B", 1), People("C", 2))) 
array.foreach(ps => Sorting.quickSort(ps)(PeopleOrdering.`By Name-Rev/Age`)) 
// > array 
// Array[Array[People]] = Array(
// Array(People(Bob,20), People(Bob,50), People(Alice,40)), 
// Array(People(C,2), People(B,1)) 
//) 
+0

Cảm ơn, nó rất hữu ích. – Abdulrahman

1

Ví dụ của bạn, nơi bạn muốn đặt hàng String s desceding thêm điều này trước khi sắp xếp

implicit object ReverseStringOrdering extends Ordering[String] { 
    def compare(x: String, y: String) = -1 * x.compareTo(y) 
    } 

Vì vậy, nói chung chỉ cần thêm đối tượng ngụ ý Ordering loại bạn muốn sắp xếp giảm dần với phương thức compare bị ghi đè. Giải pháp này chỉ hoạt động nếu bạn sắp xếp theo các loại khác nhau.

Nếu bạn muốn sắp xếp theo tăng dần mục đầu tiên và giảm dần thứ hai thêm điều này trước khi sắp xếp:

implicit def AscFirstDescSecondTuple2[T1, T2](implicit ord1: Ordering[T1], ord2: Ordering[T2]): Ordering[(T1, T2)] = 
    new Ordering[(T1, T2)]{ 
     def compare(x: (T1, T2), y: (T1, T2)): Int = { 
     val compare1 = ord1.compare(x._1, y._1) 
     if (compare1 != 0) return compare1 
     val compare2 = -1 * ord2.compare(x._2, y._2) 
     if (compare2 != 0) return compare2 
     0 
     } 
    } 
+0

Đây không phải là những gì tôi đang tìm kiếm. Tôi muốn sắp xếp mục đầu tiên, tăng dần thứ hai giảm dần và như vậy trên – Abdulrahman

+0

Các mục này có cùng loại không? – ka4eli

+0

Bạn có thể nói điều đó. – Abdulrahman

Các vấn đề liên quan