使用排序来排序数组,升序和降序

时间:2015-07-26 11:37:54

标签: arrays scala sorting

我想按第3和第1个元素对元组数组进行排序,所以我使用了以下代码:

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

我的问题是,在前面的例子中,我可以按第三个和第一个元素升序排序,或者两个元素都降序(使用反向)。但是如何按第三个元素升序和第一个元素降序排序。

请在答案中考虑以下情况:

Array[Array[People]]  

在这种情况下,我不知道内部数组的确切大小(取决于我读入此数组的文件架构),我想按侧面的所有项目排序(一些升序和一些降序)。

编辑: 看起来,我很想念。

以下是我的完整案例: 我有以下课程:

  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

我想做一个像这样的代码。

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

模式或内部数组将根据输入文件进行更改(在示例中,它是Double,String,String,Double但它可能是Double,Double或其他内容)。 我想找到一种方法来排序,覆盖内部数组的所有情况(关于类型和长度),升序和降序。

我目前所做的是将内部数组更改为Iterable,然后使用Ordering [Iterable [GValue]]进行排序或排序[Iterable [GValue]]。reverse。但我想按分开的方向排序(第一列升序,然后降序为第二列,然后升至第三列,依此类推)

2 个答案:

答案 0 :(得分:3)

使用Régis Jean-Gilles' CompositeOrdering from another question,我们可以撰写多个// 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))

Array[GValue]

现在我们可以对intervals类型的数组进行排序,您可以使用sortByintervals.sortBy(_._3)(`By Col3-Desc/Col1`) 进行排序:

intervals

如果您想使用Sorting.quickSortOrdering数组进行排序,我们需要type Interval = (Long, Long, Array[GValue]) implicit object tupleByArray extends Ordering[Interval] { def compare(a: Interval, b: Interval) = a._3 compare b._3 } 来表示元组:

intervals

现在,您可以使用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))) // ) 进行排序
Array[People]

我在问题更新之前留下了答案:

在多个字段上排序时有great article by Eric Loots

在您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)) // ) 的情况下,这可能如下所示:

accelerator

答案 1 :(得分:1)

对于您想要订购String次序的示例,请在排序

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

因此,通常只需添加隐式Ordering类型的对象,您希望使用重写的compare方法对其进行降序排序。只有按不同类型排序时,此解决方案才有效。

如果您想按第一项升序和第二次降序排序,请在排序前添加:

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