我实现了此功能的四个正确版本。我喜欢半惯用的Scala版本,它运行得更快,更符合类似Java的实现。
groupByAndCount
:最干净,最优雅。不幸的是,它很慢。
foldImmutable
:完全内部不可变。运行得更慢。
iterateToMutable
:简单的可变版本。还是很慢。
iterateToJavaMutable
:使用Java(可变)HashMap提供计算功能,因此代码可以避免每个元素迭代的单独get / set函数。
fixedTypeLongCustomMap
:这是使用自定义非通用集合it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap
并且运行速度最快。
以下是一些jmh基准:
Benchmark Mode Cnt Score Error Units
FreqMapGenerationJava.fixedTypeLongCustomMap avgt 5 0.255 ± 0.061 s/op
FreqMapGenerationJava.foldImmutable avgt 5 3.728 ± 0.318 s/op
FreqMapGenerationJava.groupByAndCount avgt 5 1.315 ± 0.405 s/op
FreqMapGenerationJava.iterateToJavaMutable avgt 5 0.654 ± 0.080 s/op
FreqMapGenerationJava.iterateToMutable avgt 5 1.356 ± 0.240 s/op
这是完整的Scala代码:
def foldImmutable[A](l: Seq[A]): immutable.Map[A, Int] = {
def foldF(m: immutable.Map[A, Int], a: A): immutable.Map[A, Int] = {
m + (a -> (m.getOrElse(a, 0) + 1))
}
l.foldLeft(immutable.Map[A, Int]())(foldF)
}
def groupByAndCount[A](l: Seq[A]): immutable.Map[A, Int] =
l.groupBy(x => x).mapValues(l => l.size)
def iterateToMutable[A](l: Seq[A]): mutable.Map[A, Int] = {
val m = mutable.Map[A, Int]()
for (a <- l) {
m(a) = m.getOrElse(a, 0) + 1
}
m
}
def iterateToJavaMutable[A](l: Seq[A]): java.util.Map[A, Int] = {
val m = new java.util.HashMap[A, Int]()
for (a <- l) {
m.compute(a, (k, v) => if (v == null) 1 else v + 1)
}
m
}
def fixedTypeLongCustomMap(l: Seq[Long]): Long2IntOpenHashMap = {
val m = new Long2IntOpenHashMap
for (a <- l) {
m.addTo(a, 1)
}
m
}
答案 0 :(得分:1)
检查一下:
def foldImmutableAggregate[A](l: Seq[A]) : Map[A, Int] = {
l.aggregate(Map[A, Int]())({ (sum, ch) => sum ++ Map(ch -> (sum.getOrElse(ch, 0) + 1)) }, (a, b) => a ++ b)
}
或
def foldImmutableAggregate[A](l: Seq[A]) : Map[A, Int] = {
l.par.aggregate(Map[A, Int]())({ (sum, ch) => sum ++ Map(ch -> (sum.getOrElse(ch, 0) + 1)) }, (a, b) => a ++ b)
}
以块的形式处理Seq
答案 1 :(得分:0)
您是否在可变和不可变集合上尝试过Scala标准库groupBy
on Immuable Seq
scala> Seq(1, 2, 2, 2, 1, 1, 1, 4, 4).groupBy(identity).mapValues(_.size)
res16: scala.collection.immutable.Map[Int,Int] = Map(2 -> 3, 4 -> 2, 1 -> 4)
on mutable ListBuffer
scala> ListBuffer(1, 2, 1, 2).groupBy(identity).mapValues(_.size)
res17: scala.collection.immutable.Map[Int,Int] = Map(2 -> 2, 1 -> 2)