Scala 对通用对象列表进行排序
我需要编写一个对Scala 对通用对象列表进行排序,scala,Scala,我需要编写一个对Seq[T]对象执行排序的通用代码。我知道在我们知道基类及其属性之前,将不可能执行排序操作。在研究了这段代码之后,我使用了这段代码,我的要求是处理尽可能多的自定义数据类型 case class Country(name: String, id : Int) type CountrySorter = (Country, Country) => Boolean def byName : CountrySorter = (c1:Country, c2:Country) =>
Seq[T]
对象执行排序的通用代码。我知道在我们知道基类及其属性之前,将不可能执行排序操作。在研究了这段代码之后,我使用了这段代码,我的要求是处理尽可能多的自定义数据类型
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
)
input.sortWith(sortingMap(criteria))这里我得到的错误是sortWith
函数只接受Country
类型,而不接受T
类型 使用带有字符串键的地图对国家进行排序容易出错。更好的替代方法是通过ordering[A]
type类利用Scala中的排序机制
您可以这样使用它:
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)
}
您可以在case类的伴奏中定义顺序并显式导入它:
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)
}
如果需要,甚至可以显式地传递订单:
def main(args: Array[String]): Unit = {
val countries: Seq[Country] = ???
sort(countries)(Country.byNameOrdering)
}
如果您想使用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))
case类国家(名称:String,id:Int)
类型分拣机[T]=(T,T)=>布尔值
类型CountrySorter=分拣机[国家]
def byName:CountrySorter=(c1,c2)=>c1.namec1.id
使用上述答案后,我用以下代码满足了此要求
作为所有子案例类的父类的通用特征,即仅包含执行排序的字段
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
用名称保存排序顺序的数据结构
val mapper = Map[String, Sorter[Generic]](
"name" -> byName,
"id" -> byId,
"place" -> byPlace
)
输入
输出
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))
使用implicit
不是满足此要求的正确方法,因为我应该动态更改排序顺序,即我需要为每个新排序顺序在范围内引入一个新函数。@puneethredtyv动态性如何?你怎么决定?您总是可以通过自己提供排序来显式地传递排序。在我的需求中,我将从UI获取一个字符串,该字符串描述排序顺序。您在这种方法中使用了显式的,这没有什么错,但是对于这种要求,我怎么可能仅通过字符串值在范围内设置排序顺序呢?@puneethredtyv我明白您的意思。我们可以通过在字符串上切换/if-else并在范围内生成正确的顺序来实现这一点,但它可能会比使用sortWith
更麻烦。谢谢您的回答,并让我的评论令人信服。
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))