对通用对象列表进行排序

时间:2018-03-06 15:47:52

标签: scala

我需要编写一个对Seq[T]对象执行排序的通用代码。我知道赢了可以执行排序操作,直到我们知道base class及其attributes。在看了这个answer后,我采用了这个代码,我的要求是尽可能多地处理自定义数据类型。

case class Country(name: String, id : Int)
type CountrySorter = (Country, Country) => Boolean
def byName : CountrySorter = (c1:Country, c2:Country) => c1.name < c2.name
def byId : CountrySorter = (c1:Country, c2:Country) => (c1.id < c2.id)

val sortingMap = Map[String, CountrySorter](
  "sortByCountryName" -> byName ,
  "soryByCountryId" -> byId
 )

函数调用

def sort[T]( input : Seq[T], criteria : String) : Seq[T] = {
  input.sortWith(sortingMap(criteria))
}

input.sortWith(sortingMap(标准)) 在这里我收到错误,因为sortWith函数只接受Country类型,而不是{{1 }类型。

3 个答案:

答案 0 :(得分:3)

使用带有字符串类型键的SELECT ev.name, LISTAGG(user_name, ', ') WITHIN GROUP ( ORDER BY user_name DESC ) "Users" FROM events ev LEFT JOIN users u ON u.birthday >= ev.datestart AND u.birthday <= ev.dateend GROUP BY ev.name; 对国家/地区进行排序很容易出错。更好的选择是通过Map类型类利用Scala中的排序机制。

你可以像这样使用它:

Ordering[A]

这里的问题是在范围内有正确的顺序。您可以在范围内创建单个临时排序:

def sort[T](input : Seq[T])(implicit order: Ordering[T]): Seq[T] = {
  input.sorted
}

您可以在案例类的配套中定义顺序并明确导入它:

def main(args: Array[String]): Unit = {
  implicit val byIdOrdering = Ordering.by((country: Country) => country.id)

  val countries: Seq[Country] = ???
  sort(countries)
}

如果您有这样的订购规则,也可以使用low priority implicits trick

object Country {
  implicit val byIdOrdering: Ordering[Country] = 
     Ordering.by((country: Country) => country.id)

  implicit val byNameOrdering: Ordering[Country] = 
     Ordering.by((country: Country) => country.name)
}

import Country.byNameOrdering
def main(args: Array[String]): Unit = {
  val countries: Seq[Country] = ???
  sort(countries)
}

如果需要,甚至可以明确传递顺序:

trait LowPriorityCountryImplicits {
  implicit val byNameOrdering: Ordering[Country] = 
    Ordering.by((country: Country) => country.name)
}

object HighPriorityCountryImplicits extends LowPriorityCountryImplicits {
  implicit val byIdOrdering: Ordering[Country] = 
    Ordering.by((country: Country) => country.id)
}

import HighPriorityCountryImplicits._
def main(args: Array[String]): Unit = {
  val countries: Seq[Country] = ???
  sort(countries)
}

答案 1 :(得分:2)

如果您想使用sortWith

定义订购,这是一种方法
case class Country(name: String, id : Int)

type Sorter[T] = (T, T) => Boolean
type CountrySorter = Sorter[Country]

def byName : CountrySorter = (c1, c2) => c1.name < c2.name
def byId : CountrySorter = (c1, c2) => c1.id < c2.id

def sort[T](input: Seq[T], sorter: Sorter[T]): Seq[T] = {
  input.sortWith(sorter)
}

val countries = List(Country("Australia", 61), Country("USA", 1), Country("France", 33))

sort(countries, byName)
// res1: Seq[Country] = List(Country(Australia,61), Country(France,33), Country(USA,1))

sort(countries, byId)
// res2: Seq[Country] = List(Country(USA,1), Country(France,33), Country(Australia,61))

答案 2 :(得分:0)

使用上述答案后,我已通过以下代码

满足此要求

通用特征,它是所有子案例类的父级,即仅包含执行排序的字段

 sealed trait Generic{
    def name : String = ???
    def id : Int = ???
    def place : String = ???
  }

 //case class which need to be sorted 
  case class Capital( 
      countryName : String, 
      override val id: Int, 
      override val place:String
 ) extends Generic

  case class Country(
         override val name: String, 
         override val id: Int
  ) extends Generic

排序类型

  type Sorter[T] = (T, T) => Boolean
  type CountrySorter = Sorter[Generic]
  type CapitalSorter = Sorter[Generic]

排序订单

  def byName : CountrySorter = (c1, c2) => c1.name < c2.name

  def byId : CountrySorter = (c1, c2) => c1.id < c2.id

  def byPlace : CapitalSorter = (s1, s2) => s1.place > s2.place

排序方法

  def sort[T](input: Seq[T], sorter: Sorter[T]): Seq[T] = {
    input.sortWith(sorter)
  }

用于保存具有名称的排序顺序的数据结构。

  val mapper = Map[String, Sorter[Generic]](
        "name" -> byName, 
        "id" -> byId, 
        "place" -> byPlace
       )

输入

  val countries = List(Country("Australia", 61), Country("USA", 1), Country("France", 33))
  val headQuaters = List(
    Capital("Australia", 61, "Melbourne"), 
    Capital("America", 1, "New York"), 
    Capital("France", 33, "Paris"), 
    Capital("India", 65, "New Delhi")
 )

输出

  println(sort(countries,mapper("id")))
 //List(Country(USA,1), Country(France,33), Country(Australia,61))

  println(sort(headQuaters , mapper("place")))
  //List(Capital(France,33,Paris), Capital(America,1,New York), Capital(India,65,New Delhi), Capital(Australia,61,Melbourne))