1) 是什么p
意思?
groupBy
接受一个将元素映射到类型键的函数K
。当在某个集合上调用时Coll
,它返回一个Map[K, Coll]
包含从键K
到映射到同一键的所有元素的映射。
因此,在您的情况下,生成从键(这是一个字符)到包含所有元素(字符)的字符串str.groupBy(_.toChar)
的映射映射,例如. 你得到这个:k
c
k == c.toChar
Map(e -> "e", h -> "h", l -> "ll", o -> "o")
AMap
是键和值对的可迭代对象。在这种情况下,每一对都是一个字符和一串元素。调用map
a 上的操作Map
涉及到这些对上的映射 -p
是一对,其中p._1
是一个字符,并且p._2
是关联的字符串(您可以在其上调用length
,就像上面所做的那样)。
2)如何习惯性地做到这一点
以上是如何惯用地做到这一点 - 使用groupBy
and map
。或者,您可以使用不可变映射和字符串长度上的递归来计算频率,或者使用不可变映射和foldLeft
.
3) 性能特点
最好进行基准测试以查看差异。这里有几个用于高度重复字符串的微基准测试(~3GHz iMac、JDK7、Scala 2.10.0 nightly):
object Imperative extends testing.Benchmark {
val str = "abc" * 750000
def run() {
var counts = new scala.collection.mutable.HashMap[Char,Int]
var i = 0
val until = str.length
while (i < until) {
var c = str(i)
if (counts.contains(c))
counts.put(c, counts(c) + 1)
else
counts.put(c, 1)
i += 1
}
//println(f)
}
}
object Combinators extends testing.Benchmark {
val str = "abc" * 750000
def run() {
val f = str.groupBy(_.toChar).map(p => (p._1, p._2.length))
}
}
object Fold extends testing.Benchmark {
val str = "abc" * 750000
def run() {
val f = str.foldLeft(Map[Char, Int]() withDefaultValue 0){(h, c) => h.updated(c, h(c)+1)}
}
}
结果:
至关重要的:$ 103 57 53 58 53 53 53 53 53 53
组合器:$ 72 51 63 56 53 52 52 54 53 53
折叠:$ 163 62 71 62 57 57 57 58 57 57
请注意,将命令式版本更改为使用withDefaultValue
:
var counts = new scala.collection.mutable.HashMap[Char,Int].withDefaultValue(0)
var i = 0
val until = str.length
while (i < until) {
var c = str(i)
counts.put(c, counts(c) + 1)
i += 1
}
put
由于转发每个呼叫,显然非常慢:
withDefaultValue
:$ 133 87 109 106 101 100 101 100 101 101
结论:在这种情况下,字符的装箱和拆箱足够高,因此很难观察到这些方法之间的性能差异。
编辑:
更新:您可能希望使用ScalaMeter 内联基准测试来代替Benchmark
trait。