我可以计算此 Scala 片段中 1 个循环中的出现次数吗?

发布于 2024-10-05 02:55:01 字数 888 浏览 1 评论 0原文

我有一段简单的 Scala 代码。我按顺序循环遍历字符串列表,并且我想计算列表 r 中作为元组 (String, Int) 收集的每个字符串的出现次数。主函数中的部分应该保留(所以没有groupBy之类的东西)。我的问题是关于更新函数:

现在我首先执行 find ,然后向 r 添加一个新元组(如果它不存在)。如果确实存在,我会循环遍历 r 并更新匹配字符串的计数器。

能否修改更新函数,使其更加高效? r 可以在单次迭代中更新吗(如果不存在则添加,如果存在则更新计数器)?

谢谢

var r = List[(String, Int)]() // (string, count)

def update(s: String, l: List[(String, Int)]) : List[(String, Int)] = {
  if (r.find(a => a._1  == s) == None) {
    (s, 1) :: r // add a new item if it does not exist
  } else {
    for (b <- l) yield {
      if (b._1 == s) {
        (b._1, b._2 + 1) // update counter if exists
      } else {
        b // just yield if no match
      }
    }
  }
}

def main(args : Array[String]) : Unit = {
  val l = "A" :: "B" :: "A" :: "C" :: "A" :: "B" :: Nil

  for (s <- l) r = update(s, r)

  r foreach println
}

I have a simple piece of Scala code. I loop sequentially through a List of Strings, and I want to count the occurrence of each String which I collect as tuples (String, Int) in the list r. The part in the main function should remain (so no groupBy or something). My question is about the update function:

right now I do a find first, and then add a new tuple to r if it doesn't exist. If it does exist, I loop through r and update the counter for the matching String.

Can the update function be modified so that it is more efficient? Can r be updated in a single iteration (adding if it doesn't exist, updating the counter if it does exist)?

Thanks

var r = List[(String, Int)]() // (string, count)

def update(s: String, l: List[(String, Int)]) : List[(String, Int)] = {
  if (r.find(a => a._1  == s) == None) {
    (s, 1) :: r // add a new item if it does not exist
  } else {
    for (b <- l) yield {
      if (b._1 == s) {
        (b._1, b._2 + 1) // update counter if exists
      } else {
        b // just yield if no match
      }
    }
  }
}

def main(args : Array[String]) : Unit = {
  val l = "A" :: "B" :: "A" :: "C" :: "A" :: "B" :: Nil

  for (s <- l) r = update(s, r)

  r foreach println
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

内心旳酸楚 2024-10-12 02:55:07

像这样的东西也有效:

val l = List("A","B","A","C","A","B")

l.foldLeft(Map[String,Int]()) {
  case (a: Map[String, Int], s: String) => {
    a + (s -> (1 + a.getOrElse(s, 0)))
  }
}

res3: scala.collection.immutable.Map[String,Int] = Map((A,3), (B,2), (C,1))

Something like this also works:

val l = List("A","B","A","C","A","B")

l.foldLeft(Map[String,Int]()) {
  case (a: Map[String, Int], s: String) => {
    a + (s -> (1 + a.getOrElse(s, 0)))
  }
}

res3: scala.collection.immutable.Map[String,Int] = Map((A,3), (B,2), (C,1))
单身狗的梦 2024-10-12 02:55:07

您当前的解决方案非常慢,主要是因为选择 r 作为 List。但至少在更新的情况下您在整个列表中的迭代可以得到改进。我会这样写,

def update(s: String, l: List[(String, Int)]) : List[(String, Int)] = {
  l span (_._1 != s) match {
    case (before, (`s`, count) :: after) => before ::: (s, count + 1) :: after
    case _ => (s, 1) :: l
  }
}

使用 span 可以避免搜索列表两次。此外,我们只需追加after,而不必再次迭代它。

Your present solution is horribly slow, mainly because of the choice of r as a List. But your iteration throughout the whole list in case of update can be improved on, at least. I'd write it like this

def update(s: String, l: List[(String, Int)]) : List[(String, Int)] = {
  l span (_._1 != s) match {
    case (before, (`s`, count) :: after) => before ::: (s, count + 1) :: after
    case _ => (s, 1) :: l
  }
}

Using span avoids having to search the list twice. Also, we just append after, without having to iterate through it again.

少钕鈤記 2024-10-12 02:55:05

我建议您选择函数式风格并使用 Scala 集合的强大功能:

ss.groupBy(identity).mapValues(_.size)

I suggest you go for the functional style and use the power of Scala's collections:

ss.groupBy(identity).mapValues(_.size)
鹊巢 2024-10-12 02:55:05

如果您不想使用 groupBy 或使用惰性集合(流),这可能是要走的路:

ss.foldLeft(Map[String, Int]())((m, s) => m + (s -> (m.getOrElse(s, 0) + 1)))

If you don't want to use groupBy or work with lazy collections (Streams), this could be the way to go:

ss.foldLeft(Map[String, Int]())((m, s) => m + (s -> (m.getOrElse(s, 0) + 1)))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文