首页 文章

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

提问于
浏览
5

我想通过3rd和first元素对元组数组进行排序,因此我使用了以下代码:

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 回答

  • 3

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

    现在我们可以对 Array[GValue] 类型的数组进行排序,您可以使用 sortByintervals 进行排序:

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

    如果要使用 Sorting.quickSortintervals 数组进行排序,我们需要 Ordering 作为元组:

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

    现在,您可以使用 Sorting.quickSortintervals 进行排序:

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

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

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

    Array[People] 的情况下,这可能看起来像:

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

    对于您想要订购 String s降序的示例,请在排序之前添加此项

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

相关问题