加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

为Scala中的字符串生成频率映射

发布时间:2020-12-16 09:45:19 所属栏目:安全 来源:网络整理
导读:假设我有一个字符串“你好”,我想生成一个字符频率图: 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)) coun
假设我有一个字符串“你好”,我想生成一个字符频率图:

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看到差异。
这是一个高度重复的字符串(?3GHz iMac,JDK7,Scala 2.10.0夜间)的几个微型基准:

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

请注意,将命令式版本更改为使用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代替基准特征。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读