【问题标题】:Idiomatic Scala for nested loop用于嵌套循环的惯用 Scala
【发布时间】:2016-12-13 22:03:54
【问题描述】:

我正在尝试编写惯用的 scala 代码来遍历两个列表列表,并生成一个仅包含两个列表差异的新列表。

在程序化 Scala 中,我会这样做:

val first: List[List[Int]]  = List(List(1,2,3,4,5),List(1,2,3,4,5),  List(1,2,3,4,5))
val second: List[List[Int]] = List(List(1,2,3,4,5),List(1,23,3,45,5),List(1,2,3,4,5))

var diff: List[String] = List[String]()
for (i <- List.range(0, first.size)){
  for (j <- List.range(0, first(0).size)){
    println(first(i)(j) + " " + second(i)(j))
    if (first(i)(j) != second(i)(j)) diff = diff ::: (s"${second(i)(j)}" :: Nil)
  }
}

我当然不喜欢这样,我曾尝试使用 for comprehension 编写解决方案,但没有成功。

我能做到的最接近的事情是这样的:

for {(lf,ls) <- (first zip second) } yield if (lf == ls) lf else ls

但为了理解,我无法生成与输入类型不同的字符串列表。

有什么建议吗?

【问题讨论】:

  • 第一个和第二个应该是 List(List(1,2,3,4,5),List(1,2,3,4,5), List(1,2,3 ,4,5))?
  • @alva 你能否编译你的代码。类型仍然错误,first 和 second 不是 Int 类型。同样在示例中 diff 是分配给 val 的不可变列表,因此它永远不会更新。
  • @Tyth,不,我不认为是重复的。我确实理解 for 和 list 理解之间的区别。我在这里要问的是,如果有惯用的方法,关于如何在惯用的 scala 中编写嵌套 for 循环的任何建议。
  • 如果您提供示例输入和输出可能会有所帮助:)

标签: scala functional-programming


【解决方案1】:

惯用的 Scala 应该是这样的:

(
  for {
    (row1, row2) <- (first, second).zipped   // go through rows with the same index
    (value1, value2) <- (row1, row2).zipped  // go through values with the same indexes
    if value1 != value2                      // leave only different values in the list
  } yield value2.toString
).toList

这里最好使用zipped,而不是zip,因为zipped 不会在内存中生成整个压缩后的List

此外,由于类型推断的怪癖,您最后必须执行toList

【讨论】:

    【解决方案2】:

    这样的事情会产生相同的结果

    val diff = for {
      firstInner <- first
      v1 <- firstInner
      secondInner <- second
      v2 <- secondInner
    } yield if (v1 != v2) s"$v2}"
    
    println(diff2 mkString ", ") // prints 23, 45
    

    但是如果数组大小不同,这当然会失败并出现 IndexOutOfBoundsException。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多