加速迭代文本并创建 Map[Tuple2[String, String], Int] Scala 的方法
Speeding up a method that iterates through text and creates a Map[Tuple2[String, String], Int] Scala
我在 scala 程序中有一个创建 Map[Tuple2[String, String], Int] 的方法,但它 运行 非常慢并且无法处理很多文本。我似乎无法弄清楚如何加快速度并提高效率。任何建议将不胜感激。
def createTuple(words: List[String]): Map[Tuple2[String, String], Int] = {
var pairCountsImmutable = Map[Tuple2[String, String], Int]()
val pairCounts = collection.mutable.Map(pairCountsImmutable.toSeq: _*)
var i = 0
for (i <- 0 to words.length - 2) {
val currentCount: Int = pairCounts.getOrElse((words(i), words(i + 1)), 0)
if (pairCounts.exists(_ == (words(i), words(i + 1)) -> currentCount)) {
var key = pairCounts(words(i), words(i + 1))
key = key + 1
pairCounts((words(i), words(i + 1))) = key
} else {
pairCounts += (words(i), words(i + 1)) -> 1
}
}
var pairCountsImmutable2 = collection.immutable.Map(pairCounts.toList: _*)
return pairCountsImmutable2
}
你的大问题是 words
是一个 List
,而你却用 words(i)
索引它。那很慢。将其更改为 Vector
或修改算法以不使用索引。
此外,pairCounts.exists
很慢,您应该尽可能使用 contains
,因为它在地图上是常数时间。
更新
我无耻地借鉴了 TRuhland 的答案,给出了我的答案的改进版本,它不会因空列表或单元素列表而失败:
def createTuple(words: List[String]): Map[Tuple2[String, String], Int] =
words
.zip(words.drop(1))
.groupBy(identity)
.mapValues(_.length)
原创
您似乎在计算相邻的单词对是一个单词列表。如果是这样,这样的事情应该有效:
def createTuple(words: List[String]): Map[Tuple2[String, String], Int] =
words
.sliding(2)
.map(l => (l(0), l(1)))
.toList
.groupBy(identity)
.mapValues(_.length)
工作原理如下
sliding(2)
创建相邻词对列表
map
将每对从 List
变成元组
groupBy
将具有相同值的元组分组
mapValues
统计每对有相同值的对数
这可能不是您想要的,但希望它能让您了解如何完成。
作为一般规则,不要使用索引遍历列表,而是尝试将列表转换为可以遍历值的内容。
尽量不要逐个创建 Map
s。使用 groupBy
或 toMap
.
如果我们首先将您的代码简化为本质:
def createTuple(words: List[String]): Map[(String, String), Int] = {
val pairCounts = collection.mutable.Map[(String, String), Int]()
for (i <- 0 until words.length - 1) {
val pair = (words(i), words(i + 1))
pairCounts += (pair -> (pairCounts.getOrElse(pair, 0) + 1))
}
pairCounts.toMap
}
为了提高速度,不要在列表上使用索引(如其他地方所述):
def createTuple(words: List[String]): Map[(String, String), Int] = {
val map = collection.mutable.Map[(String, String), Int]()
words
.zip(words.tail)
.foreach{ pair =>
map += (pair -> (map.getOrElse((pair, 0) + 1)) }
map.toMap
}
我在 scala 程序中有一个创建 Map[Tuple2[String, String], Int] 的方法,但它 运行 非常慢并且无法处理很多文本。我似乎无法弄清楚如何加快速度并提高效率。任何建议将不胜感激。
def createTuple(words: List[String]): Map[Tuple2[String, String], Int] = {
var pairCountsImmutable = Map[Tuple2[String, String], Int]()
val pairCounts = collection.mutable.Map(pairCountsImmutable.toSeq: _*)
var i = 0
for (i <- 0 to words.length - 2) {
val currentCount: Int = pairCounts.getOrElse((words(i), words(i + 1)), 0)
if (pairCounts.exists(_ == (words(i), words(i + 1)) -> currentCount)) {
var key = pairCounts(words(i), words(i + 1))
key = key + 1
pairCounts((words(i), words(i + 1))) = key
} else {
pairCounts += (words(i), words(i + 1)) -> 1
}
}
var pairCountsImmutable2 = collection.immutable.Map(pairCounts.toList: _*)
return pairCountsImmutable2
}
你的大问题是 words
是一个 List
,而你却用 words(i)
索引它。那很慢。将其更改为 Vector
或修改算法以不使用索引。
此外,pairCounts.exists
很慢,您应该尽可能使用 contains
,因为它在地图上是常数时间。
更新
我无耻地借鉴了 TRuhland 的答案,给出了我的答案的改进版本,它不会因空列表或单元素列表而失败:
def createTuple(words: List[String]): Map[Tuple2[String, String], Int] =
words
.zip(words.drop(1))
.groupBy(identity)
.mapValues(_.length)
原创
您似乎在计算相邻的单词对是一个单词列表。如果是这样,这样的事情应该有效:
def createTuple(words: List[String]): Map[Tuple2[String, String], Int] =
words
.sliding(2)
.map(l => (l(0), l(1)))
.toList
.groupBy(identity)
.mapValues(_.length)
工作原理如下
sliding(2)
创建相邻词对列表map
将每对从List
变成元组groupBy
将具有相同值的元组分组mapValues
统计每对有相同值的对数
这可能不是您想要的,但希望它能让您了解如何完成。
作为一般规则,不要使用索引遍历列表,而是尝试将列表转换为可以遍历值的内容。
尽量不要逐个创建 Map
s。使用 groupBy
或 toMap
.
如果我们首先将您的代码简化为本质:
def createTuple(words: List[String]): Map[(String, String), Int] = {
val pairCounts = collection.mutable.Map[(String, String), Int]()
for (i <- 0 until words.length - 1) {
val pair = (words(i), words(i + 1))
pairCounts += (pair -> (pairCounts.getOrElse(pair, 0) + 1))
}
pairCounts.toMap
}
为了提高速度,不要在列表上使用索引(如其他地方所述):
def createTuple(words: List[String]): Map[(String, String), Int] = {
val map = collection.mutable.Map[(String, String), Int]()
words
.zip(words.tail)
.foreach{ pair =>
map += (pair -> (map.getOrElse((pair, 0) + 1)) }
map.toMap
}