加速迭代文本并创建映射[Tuple2[String,String],Int]Scala的方法

加速迭代文本并创建映射[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

我在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
}
你最大的问题是单词是一个列表,而你却在用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您使用可变映射还是不可变映射?我当然假设是可变的。使用可变映射可能比每次创建新映射快得多。使用可变映射可能比每次创建新映射快得多。