为Scala中的字符串生成频率映射
假设我有一个字符串“你好”,我想生成一个字符频率图:
Map[Char,Int] = Map(h -> 1,e -> 1,o -> 1,l -> 2) 我可以反复地做这个: val str = "hello" var counts = new scala.collection.mutable.HashMap[Char,Int] for (i <- str) { if (counts.contains(i)) counts.put(i,counts(i) + 1) else counts.put(i,1) } 通过在REPL中混乱,我发现我可以做一些更简洁的事情,而不是使用可变的集合: > str.groupBy(_.toChar).map{ p => (p._1,p._2.length)} scala.collection.immutable.Map[Char,l -> 2) 但是我不知道groupBy()的性能特征,也不知道传递给map的块正在发生什么(像什么,确切的是p)。 我如何用Scala中的功能范例成语? 对于背景,我刚刚从Ruby来到Scala。在Ruby中,我将使用注入,但我不知道在Scala中如何并行的方法是: counts = str.each_byte.inject(Hash.new(0)){ |h,c| h[c] += 1; h} 解决方法
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") 地图是一组可重复的键和值。在这种情况下,每对都是一个字符和一串元素。在地图上调用地图操作涉及对这些对的映射 – p是一对p._1是一个字符,p._2是相关联的字符串(可以在其上调用长度,如上所述)。 2)如何做这个惯用的 以上是如何做成语 – 使用groupBy和map。或者,您可以使用字符串长度上的不可变地图和递归来计算频率,或使用不可变地图和foldLeft。 3)性能特点 最好到benchmark看到差异。 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 请注意,将命令式版本更改为使用DefaultValue: 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 } 由于转发每个拨打电话显然非常慢: > withDefaultValue:$ 133 87 109 106 101 100 101 100 101 101 结论:在这种情况下,字符的拳击和拆箱是足够高的,所以这些方法之间的性能差异很难观察。 编辑: 更新:您可能要使用ScalaMeter inline benchmarking代替基准特征。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |