提升algebird聚合器以使用(并返回)Map

时间:2017-02-06 01:36:18

标签: scala algebird

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))

本质上,Map的使用等同于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]类型的值进行操作的聚合器(对于某些任意{{ 1}})?

1 个答案:

答案 0 :(得分:0)

对于Semigroup,至少可以相当容易地完成此操作。在"撰写"中没有额外逻辑的情况下,这应该足够了。或"现在"需要保留聚合器的阶段(Semigroup可以从Aggregator获得,丢弃撰写/准备)。

回答原始问题的代码是:

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)