Scala - 计算迭代器中每个键的出现次数

jay*_*ker 1 iterator scala

我有一个包含一些键值对的迭代器.例如

(jen,xyz)(ken,zxy)(jen,asd)(ken,asdf)

结果应该是

(jen,2)(ken,2)

如何使用count函数(或任何其他函数)计算该特定集合的迭代器中每个键的出现次数.

编辑: 此迭代器在我的用例中表示的集合具有大量记录,可能在数百万的范围内,不需要最有效(时间复杂度较低)的方法来执行此操作.我发现默认计数方法非常快,并且可以某种方式用于产生期望结果.

Jas*_*man 11

Peter Neyens建议的方法可行,但由于方式和使用方式toList,某些应用程序可能效率非常低(时间和内存).将计数直接聚合到地图中并避免所有不必要的创建通常会更有效.groupBylengthLists

import scala.collection.TraversableOnce
import scala.collection.mutable.HashMap

def counts[T](xs: TraversableOnce[T]): Map[T, Int] = {
  xs.foldLeft(HashMap.empty[T, Int].withDefaultValue(0))((acc, x) => { acc(x) += 1; acc}).toMap
}
Run Code Online (Sandbox Code Playgroud)

一旦定义了counts方法,就可以将它应用到键值对的迭代器中,如下所示:

val iter: Iterator[(String, String)] = ???
val keyCounts = counts(iter.map(_._1))
Run Code Online (Sandbox Code Playgroud)

counts上面定义的方法适用Iterators于大量的值,例如

val iter = Iterator.range(0, 100000000).map(i => (i % 1931, i))
val countMap = counts(iter.map(_._1))
// Map(645 -> 51787, 892 -> 51787, 69 -> 51787, 1322 -> 51786, ...)
Run Code Online (Sandbox Code Playgroud)

工作正常,而在Peter的回答中提出的方法,即

val iter = Iterator.range(0, 100000000).map(i => (i % 1931, i))
val countMap = iter.toList.groupBy(_._1).mapValues(_.length).toMap
Run Code Online (Sandbox Code Playgroud)

离开一段时间,最终导致一个OutOfMemoryError.它失败的原因是因为所有不必要的List创造.


Pet*_*ens 5

您可以groupBy键,然后计算每个键的出现次数:

val iterator = 
  Iterator(("jen","xyz"), ("ken","zxy"), ("jen","asd"), ("ken", "asdf"))

iterator.toList.groupBy(_._1).mapValues(_.length).toList
// List[(String, Int)] = List((jen,2), (ken,2))
Run Code Online (Sandbox Code Playgroud)

  • @JasonLenderman,"非常低效"?对于绝大多数案件来说,几乎肯定不会有所作为.微观优化只是愚蠢,直到你真的*需要它们(这是非常罕见的).**加上**,如果你真的*关注那么微小的效率,你应该重写*你的答案,不要使用'foldLeft`; 毕竟,`while`循环总是会更有效率...... (2认同)