加速迭代文本并创建映射[Tuple2[String,String],Int]Scala的方法
我在scala程序中有一个方法,它正在创建一个Map[Tuple2[String,String],Int],但运行速度非常慢,无法处理太多的文本。我似乎不知道如何加快速度,提高效率。如有任何建议,将不胜感激加速迭代文本并创建映射[Tuple2[String,String],Int]Scala的方法,scala,text-processing,Scala,Text Processing,我在scala程序中有一个方法,它正在创建一个Map[Tuple2[String,String],Int],但运行速度非常慢,无法处理太多的文本。我似乎不知道如何加快速度,提高效率。如有任何建议,将不胜感激 def createTuple(words: List[String]): Map[Tuple2[String, String], Int] = { var pairCountsImmutable = Map[Tuple2[String, String], Int]() va
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
}
你最大的问题是单词是一个列表,而你却在用wordsi索引它。太慢了。将其更改为向量或修改算法以不使用索引
另外,pairCounts.exists速度较慢,您应该尽可能使用contains,因为它在地图上是恒定时间 你最大的问题是单词是一个列表,而你却在用words索引它。太慢了。将其更改为向量或修改算法以不使用索引
另外,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)
其工作原理如下
滑动2创建相邻单词对的列表
映射将列表中的每一对转换为元组
groupBy将具有相同值的元组分组
mapValues统计每对具有相同值的对数
这可能不是你想要的,但希望它能给出一个如何实现的想法
一般来说,不要使用索引遍历列表,而是尝试将列表转换为可以遍历值的内容
尽量不要逐个元素创建贴图。使用groupBy或toMap。更新
我无耻地借用了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)
其工作原理如下
滑动2创建相邻单词对的列表
映射将列表中的每一对转换为元组
groupBy将具有相同值的元组分组
mapValues统计每对具有相同值的对数
这可能不是你想要的,但希望它能给出一个如何实现的想法
一般来说,不要使用索引遍历列表,而是尝试将列表转换为可以遍历值的内容
尽量不要逐个元素创建贴图。使用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 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
}
var i=0是不必要的,if的第一个分支可以缩短为PairCountSaveri,wordsi+1+=1,但这两个分支都不会显著提高速度,只是可读性。如果读取文本是一种io操作,您可以尝试使用scala futures。我是否可以建议将其发布到codereview.stackexchange.com?他们将能够在速度和可读性方面提供更多帮助。var i=0是不必要的,if的第一个分支可以缩短为paircountshivi,wordsi+1+=1,但这两个分支都不会显著提高速度,只是可读性。如果阅读文本是一项io操作,您可以尝试使用scala futures。我是否可以建议将此发布到codereview.stackexchange.com?他们将能够在速度和可读性方面提供更多帮助。如果单词少于2个元素,这将引发异常。然而,OP的代码,在这种情况下,似乎返回一个空映射。我假设通过逐元素更新来创建带有计数的映射实际上比groupBy快,而无需为每个键分配集合。@Victor它更具可读性,而且仍然比OP的代码快得多。@VictorMoroz使用groupBy更新的速度比我使用的逐元素更新的速度快易于理解的tests@TRuhland您使用可变映射还是不可变映射?我当然假设是可变的。如果单词少于2个元素,这将抛出一个异常。然而,OP的代码,在这种情况下,似乎返回一个空映射。我假设通过逐元素更新来创建带有计数的映射实际上比groupBy快,而无需为每个键分配集合。@Victor它更具可读性,而且仍然比OP的代码快得多。@VictorMoroz使用groupBy更新的速度比我使用的逐元素更新的速度快易于理解的tests@TRuhland您使用可变映射还是不可变映射?我当然假设是可变的。使用可变映射可能比每次创建新映射快得多。使用可变映射可能比每次创建新映射快得多。