【问题标题】:How to consecutive and non-consecutive list in scala?如何在scala中连续和非连续列表?
【发布时间】:2019-12-01 23:10:48
【问题描述】:
val keywords = List("do", "abstract","if")

val resMap = io.Source
               .fromFile("src/demo/keyWord.txt")
               .getLines()
               .zipWithIndex
       .foldLeft(Map.empty[String,Seq[Int]].withDefaultValue(Seq.empty[Int])){
         case (m, (line, idx)) =>
           val subMap = line.split("\\W+")
                            .toSeq  //separate the words
                            .filter(keywords.contains)  //keep only key words
                            .groupBy(identity)  //make a Map w/ keyword as key
                            .mapValues(_.map(_ => idx+1))  //and List of line numbers as value
                            .withDefaultValue(Seq.empty[Int])
           keywords.map(kw => (kw, m(kw) ++ subMap(kw))).toMap
       }

println("keyword\t\tlines\t\tcount")
keywords.sorted.foreach{kw =>
  println(kw + "\t\t" +
          resMap(kw).distinct.mkString("[",",","]") + "\t\t" +
          resMap(kw).length)
}

此代码不是我的,我不拥有它......用于学习目的。但是,我仍在学习,并且我被困在实现连续到非连续列表中,例如“if”一词在多行中,当出现三个或更多连续行号时,它们之间应该用破折号书写,例如20-22,但不是 20、21、22。我该如何实施?我就是想学这个。

输出:

keyword     lines       count
abstract    [1]         1
do          [6]         1
if      [14,15,16,17,18]    5

但我希望结果类似于 [14-18] 因为单词“if”在第 14 到 18 行。

【问题讨论】:

    标签: scala scala-collections


    【解决方案1】:

    首先,我会按照惯例提出警告,即 SO 并不是一个众包家庭作业或项目答案的地方。我会让你怀疑事实并非如此。

    也就是说,我希望你能从这个建议中对解决这个问题有所了解:

    1. 您现有的实现没有任何东西可以了解 int 值是否确实是连续的,因此您需要添加一些代码来对从 resMap(kw).distinct 返回的 Ints 进行排序,以便为下一步。你可以弄清楚如何做到这一点。
    2. 然后您需要将Ints 按其连续性质进行分组。例如,如果您有(14,15,16,18,19,20,22),那么这确实需要进一步分组到((14,15,16),(18,19,20),(22))。你可以为此想出你的算法。
    3. 映射外部集合(此时为Seq[Seq[Int]]),根据内部Seq 的长度是否大于1 进行不同的处理。如果大于1,您可以安全地调用headtail 获得渲染范围所需的 Ints。或者,您可以更惯用地进行理解,将headOptiontailOption 中的值组合起来以构建相同的范围字符串。您在问题中提到了长度为 3 的内容,因此您可以根据需要调整此步骤以满足该需求。
    4. 最后,现在您的 Seq[String] 看起来像 ("14-16","18-20","22") ,您需要使用 mkString 调用来连接在一起,类似于您已经拥有的方括号

    作为参考,您应该进一步了解 Seq 特征的 Scaladoc:

    https://www.scala-lang.org/api/2.12.8/scala/collection/Seq.html

    【讨论】:

    • 非常感谢先生,它现在让我明白了,这段代码是你的。 :) 这一步很容易理解。非常感谢你
    【解决方案2】:

    这是一种解决方法。

    def collapseConsecutives(nums :Seq[Int]) :List[String] =
      nums.foldRight((nums.last, List.empty[List[Int]])) {
        case (n, (prev,acc)) if prev-n == 1 => (n, (n::acc.head) :: acc.tail)
        case (n, ( _  ,acc))                => (n, List(n) :: acc)
      }._2.map{ ns =>
        if (ns.length < 3) ns.mkString(",")  //1 or 2 non-collapsables
        else s"${ns.head}-${ns.last}"        //3 or more, collapsed
      }
    

    用法:

    println(kw + "\t\t" +
            collapseConsecutives(resMap(kw).distinct).mkString("[",",","]") + "\t\t" +
            resMap(kw).length)
    

    【讨论】:

    • collapseConsecutives(fileMap("kw").distinct).mkString("[",","]") + "\t\t" 它给了我错误 java.util.NoSuchElementException
    • 亲爱的先生,我已经设法欺骗了连续行实施。然而,“如果”这个词似乎只是在工作,而不是其他词先生。 println("Keyword\t\tLines\t\tCount\t\tContains") keywords.sortWith(comp).foreach{kw =&gt; println("\n "+ kw ++"\n\t\t"+ collapseConsecutives(fileMap(kw).distinct).headOption.mkString("[",",","-")+ collapseConsecutives(fileMap(kw).distinct).tail.drop(2).mkString("",",","]") + "\t\t" + "\n\t\t\t\t"+ fileMap(kw).length + "\t\t" + "" + kw.contains("do") )
    • 我认为它只需要 2 个字符的单词先生,它适用于 do 但是,在文本文件中,单词需要重复 3 次,否则它将起作用,否则它不起作用@jwvh
    • 我的“用法”示例中有一个错字(现已更正)。如您所见,我的代码建议只处理Seq[Int] 输入。如果您在代码中的其他地方遇到字长问题,那么也许您应该发布一个新问题。
    猜你喜欢
    • 2011-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-12
    • 2023-03-22
    • 1970-01-01
    相关资源
    最近更新 更多