Scala:如何为类定义自定义groupBy(就像订购一样)

时间:2018-01-20 01:05:57

标签: scala

我有这个

case class Box(id: Long, version: String)
object Box {
  implicit def ordering[A <: Box]: Ordering[A] = Ordering.by(_.version)
}
val list1 = List(new Box(0, "A"), new Box(1, "B"), new Box(0, "C"), new Box(2, "D"), new Box(1, "E"))
val list2 = List(new Box(0, "W"), new Box(4, "X"), new Box(0, "Y"), new Box(3, "F"))

trait Aggregator[U] {
   def combOp(l: ListBuffer[U], r: ListBuffer[U]): ListBuffer[U]
}

我有类似下面的内容,即groupsBy id然后在每个组中按版本排序并选择最新的

 class GroupByAndTakeLatestAggregator extends Aggregator[Box] {
    override def combOp(l1: ListBuffer[Box], l2: ListBuffer[Box]) = {
       ListBuffer((l1 ++= l2).groupBy(_.id).values.map(_.sorted.reverse.head)).flatten
    }
 }

我的问题是我如何编写GroupByAndTakeLatestAggregator的泛型版本,它知道如何在每个组中使用groupBy然后如何sortBy,假设该类定义了一个隐式排序并且可以在一个字段上进行分组。

基本上我正在寻找的是一种指定泛型groupBy trait / class的方法,就像“Ordering”一样。

1 个答案:

答案 0 :(得分:0)

groupBy操作适用于某些类型A参数化的迭代,并且需要A => B的函数B,其中==定义为A => B有意义的方式因此,我们所需要的只是提供隐式A => B函数。但是,使用非常通用的类型Grouping[A, B]将不必要污染隐含空间。因此,最好定义一个特征A => B,它基本上只是Box的一个微不足道的子特征。然后我们可以简单地在Grouping[A, B]类的伴随对象中提供隐式分组,并通过所需的Ordering[A]/** Essentially a function that groups instances of * type `I` by some feature `F` */ trait Grouping[I, F] extends (I => F) object Grouping { def by[I, F](f: I => F) = new Grouping[I, F] { def apply(i: I) = f(i) } } case class Box(id: Long, version: String) object Box { implicit def ordering[A <: Box]: Ordering[A] = Ordering.by(_.version) implicit def grouping[A <: Box]: Grouping[A, Long] = Grouping.by(_.id) } val list1 = List(new Box(0, "A"), new Box(1, "B"), new Box(0, "C"), new Box(2, "D"), new Box(1, "E")) val list2 = List(new Box(0, "W"), new Box(4, "X"), new Box(0, "Y"), new Box(3, "F")) trait Aggregator[U] { def combOp(l: List[U], r: List[U]): List[U] } class GroupingAndTakeLatestAggregator[B, F]( grp: Grouping[B, F], ord: Ordering[B] ) extends Aggregator[B] { override def combOp(l1: List[B], l2: List[B]) = { // tried to understand what it did, rewrote it a bit... for (vs <- (l1 ++ l2).groupBy(grp).values.toList) yield vs.sorted(ord).reverse.head } } // Not sure whether you want it. Implicits can quickly pollute everything. implicit def groupableAndOrderedIsAggregatable[B, F] (implicit grp: Grouping[B, F], ord: Ordering[B]): Aggregator[B] = new GroupingAndTakeLatestAggregator(grp, ord) // Little test, just to see whether an // aggregator is constructed automatically // on-demand def aggregate[A] (as: List[A], bs: List[A]) (implicit aggr: Aggregator[A]): List[A] = aggr.combOp(as, bs) println(aggregate(list1, list2)) 来参数化GBATLA-thing。这是一个例子:

$args