2015-07-26 5 views
5

Ich mag würde eine Reihe von Tupeln durch dritte und erste Element sortieren, damit ich den folgenden Code verwendet:Verwendung von Bestellung Array von Arrays zu sortieren, aufsteigend und absteigend

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

Meine Frage ist, dass in der vorheriges Beispiel Ich kann sowohl nach dem dritten als auch nach dem ersten aufsteigenden Element oder nach beiden absteigenden Elementen sortieren (umgekehrt). aber wie man nach dem dritten Element aufsteigend und nach dem ersten Element absteigend sortiert.

bitte in Ihrer Antwort den folgenden Fall betrachten:

Array[Array[People]] 

wo ich in diesem Fall nicht die genaue Größe des inneren Array weiß (abhängig von dem Dateischema, das ich in diesen Array lesen) und Ich möchte nach allen Elementen in der Seite sortieren (einige aufsteigend und einige absteigend).

Edit: Es sieht aus, ich habe Miss verstanden.

Hier ist mein voller Fall: ich die folgenden Klassen:

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 

und ich mag, wie diese einen Code zu tun.

// (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")))) 

Das Schema oder die innere Anordnung würde auf der Eingabedatei basierend ändern (im Beispiel ist es Double, String, String, Double, aber es könnte Double, Double oder etwas anderes sein). Ich würde gerne einen Weg finden, ohne alle Fälle der inneren Anordnung (in Bezug auf Typ und Länge), aufsteigend und absteigend zu sortieren.

was ich derzeit mache, ist das innere Array in Iterable zu ändern und dann Ordering [Iterable [GValue]] zum Sortieren oder Bestellen [Iterable [GValue]] zu verwenden. Aber ich möchte in getrennten Richtungen sortieren (für die erste Spalte aufsteigend und dann absteigend für die zweite dann in den dritten aufsteigend und so weiter)

+0

Sie wollen die 'Einsatz der Array sortieren, basierend auf einige der Elemente des' Array [Gwert] '? –

+0

@Peter Neyens, Ja, Sie haben völlig Recht :) – Abdulrahman

Antwort

3

Régis Jean-Gilles' CompositeOrdering from another question verwenden, können wir mehrere Orderings komponieren.

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

Jetzt können wir ein Array vom Typ Array[GValue] sortieren, und Sie könnten sortieren Sie Ihre intervals mit sortBy:

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

Wenn Sie das intervals Array mit Sorting.quickSort sortieren wollen, müssen wir eine Ordering für die Tupel:

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

Jetzt können Sie Ihre intervals mitsortieren:

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

Ich lasse meine Antwort aus der Zeit vor der Frage wurde aktualisiert:

Es gibt eine great article by Eric Loots auf mehreren Feldern Sortierung auf.

In Ihrem Fall von Array[People] dies könnte wie folgt aussehen:

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

Danke, es war so hilfreich. – Abdulrahman

1

Für Ihr Beispiel, in dem Sie String s desceding dieses Add bestellen möchten vor dem Sortieren

Also, im Allgemeinen fügen Sie einfach implizite Ordering Objekt des Typs, den Sie absteigend mit übersteuert compare Methode sortieren möchten. Diese Lösung funktioniert nur, wenn Sie nach verschiedenen Typen sortieren.

Wenn Sie diese sortieren möchten, indem zuerst Element auf- und absteigenden zweiten hinzufügen, vor dem Sortieren:

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

Dies ist nicht, was ich suche. Ich möchte den ersten Artikel sortieren, aufsteigend den zweiten absteigend usw. – Abdulrahman

+0

Sind diese Artikel vom gleichen Typ? – ka4eli

+0

Das können Sie sagen. – Abdulrahman

Verwandte Themen