1) とはp
どういう意味ですか?
groupBy
要素を type のキーにマップする関数を取りますK
。一部のコレクションで呼び出されると、キーから同じキーにマップされたすべての要素へのマッピングを含む をColl
返します。Map[K, Coll]
K
したがって、あなたの場合、キー(文字)からすべての要素(文字)を含む文字列へのstr.groupBy(_.toChar)
マップマッピングを生成します. あなたはこれを得る:k
c
k == c.toChar
Map(e -> "e", h -> "h", l -> "ll", o -> "o")
AMap
は、キーと値のペアの iterable です。この場合、各ペアは文字と要素の文字列です。map
で操作を呼び出すにはMap
、これらのペアのマッピングが含まれますp
。p._1
は文字であり、p._2
は関連付けられた文字列です (length
上記のように を呼び出すことができます)。
2)慣用的にこれを行う方法
上記は慣用的に行う方法です - と を使用groupBy
し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
を使用することもできます。