我经常需要做类似以下的事情:
什么是实现相同效果的最佳方法,但避免使用
coll.groupBy(f(_)).mapValues(_.foldLeft(x)(g(_,_)))
什么是实现相同效果的最佳方法,但避免使用
groupBy
显式构建中间集合?coll.groupBy(f(_)).mapValues(_.foldLeft(x)(g(_,_)))
groupBy
显式构建中间集合?def groupFold[A,B,X](as: Iterable[A], f: A => B, init: X, g: (X,A) => X): Map[B,X] =
as.foldLeft(Map[B,X]().withDefaultValue(init)){
case (m,a) => {
val key = f(a)
m.updated(key, g(m(key),a))
}
}
m :+ m.get(f(a)).map(g(_,a)).getOrElse(g(init,a))
简化为 m :+ m.getOrElse(f(a), init).map(g(_,a))
。 - john sullivan如果您需要像这样更复杂的代码(从性能方面考虑,因为您要求“高效”),则无法使用一行代码完成,因此在编写之前请确定您确实需要它:
final case class Var[A](var value: A) { }
def multifold[A,B,C](xs: Traversable[A])(f: A => B)(zero: C)(g: (C,A) => C) = {
import scala.collection.JavaConverters._
val m = new java.util.HashMap[B, Var[C]]
xs.foreach{ x =>
val v = {
val fx = f(x)
val op = m.get(fx)
if (op != null) op
else { val nv = Var(zero); m.put(fx, nv); nv }
}
v.value = g(v.value, x)
}
m.asScala.mapValues(_.value)
}
基于您的使用情况,您可能希望在最后一步中打包成不可变映射。以下是其示例:
scala> multifold(List("salmon","herring","haddock"))(_(0))(0)(_ + _.length)
res1: scala.collection.mutable.HashMap[Char,Int] = Map(h -> 14, s -> 6)
现在,您可能会注意到一些奇怪的地方:我正在使用Java HashMap。这是因为Java的HashMap比Scala的快2-3倍。(您可以使用Scala HashMap编写等效的内容,但实际上并不比原始内容更快。) 因此,这个操作比您发布的内容快2-3倍。但除非您受到严重的内存压力,否则创建短暂的集合并不会对您造成太大的伤害。