README中的示例非常优雅:
scala> Map(1 -> Max(2)) + Map(1 -> Max(3)) + Map(2 -> Max(4))
res0: Map[Int,Max[Int]] = Map(2 -> Max(4), 1 -> Max(3))
从本质上讲,这里使用的映射等同于SQL的group by
。
但是我如何用一个任意的聚合器做同样的事情呢?例如,为了实现与上面的代码相同的功能(但没有Max
包装类):
scala> import com.twitter.algebird._
scala> val mx = Aggregator.max[Int]
mx: Aggregator[Int,Int,Int] = MaxAggregator(scala.math.Ordering$Int$@78c77)
scala> val mxOfMap = // what goes here?
mxOfMap: Aggregator[Map[Int,Int],Map[Int,Int],Map[Int,Int]] = ...
scala> mxOfMap.reduce(List(Map(1 -> 2), Map(1 -> 3), Map(2 -> 4)))
res0: Map[Int,Int] = Map(2 -> 4, 1 -> 3)
换句话说,如何将操作T
类型的值的聚合器转换(或“提升”)为操作Map[K,T]
类型的值的聚合器(对于某些任意的K
)?
发布于 2017-02-06 02:50:05
看起来至少对于Semigroup
来说这是相当容易的。如果在聚合器的"compose“或"present”阶段中没有需要保留的额外逻辑(可以从Aggregator
获得Semigroup
,丢弃compose/prepare),这就足够了。
回答原始问题的代码是:
scala> val sgOfMap = Semigroup.mapSemigroup[Int,Int](mx.semigroup)
scala> val mxOfMap = Aggregator.fromSemigroup(sgOfMap)
scala> mxOfMap.reduce(List(Map(1 -> 2), Map(1 -> 3), Map(2 -> 4)))
res0: Map[Int,Int] = Map(2 -> 4, 1 -> 3)
但在实践中,最好从直接构造任意Semigroup
开始,而不是仅仅为了从以下位置提取半组而构造Aggregator
:
scala> import com.twitter.algebird._
scala> val mx = Semigroup.from { (x: Int, y: Int) => Math.max(x, y) }
scala> val mxOfMap = Semigroup.mapSemigroup[Int,Int](mx)
scala> mxOfMap.sumOption(List(Map(1 -> 2), Map(1 -> 3), Map(2 -> 4)))
res33: Option[Map[Int,Int]] = Some(Map(2 -> 4, 1 -> 3))
或者,转换为聚合器:Aggregator.fromSemigroup(mxOfMap)
https://stackoverflow.com/questions/42059276
复制