我有这个
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”一样。
答案 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