【问题标题】:Accessing the index of a particular cell in Scala在 Scala 中访问特定单元格的索引
【发布时间】:2013-12-05 02:02:05
【问题描述】:

我必须编写一个返回元组列表的方法“all()”;当函数满足列表中的 0 时,每个元组将包含与特定给定行和列相关的行、列和集合。我已经编写了返回我需要的集合部分的“hyp”函数,例如:Set(1,2)。我正在使用列表列表:

 | 0 | 0 | 9 |
 | 0 | x | 0 |
 | 7 | 0 | 8 |

如果 Set (1,2) 引用标记为 x 的单元格,all() 应返回: (1,1, Set(1,2)) 其中 1,1 是行和列的索引。 我使用 zipWithIndex 编写了这个方法。在没有 zipWithIndex 的情况下,有没有更简单的方法可以访问索引?提前致谢 代码:

 def all(): List[(Int, Int, Set[Int])] = 
 {
  puzzle.list.zipWithIndex flatMap 
  { 
    rowAndIndex =>
    rowAndIndex._1.zipWithIndex.withFilter(_._1 == 0) map 
    { 
      colAndIndex =>
      (rowAndIndex._2, colAndIndex._2,  hyp(rowAndIndex._2, colAndIndex._2)) 
    }
  }
 }  

(_._1 == 0 ) 是因为函数只有在网格中找到 0 时才返回 (Int,Int, Set())

【问题讨论】:

    标签: scala collections


    【解决方案1】:

    使用 zipWithIndex 相当普遍。可以通过元组中的模式匹配变量来最小化与元组/对的摔跤:

    def all(grid: List[List[Int]]): List[(Int, Int, Set[Int])] =
      grid.zipWithIndex flatMap {case (row, r) =>
        row.zipWithIndex.withFilter(_._1 == 0) map {case (col, c) => (r, c,  hyp(r, c))}
      }
    

    可以转换为100%等价的理解:

    def all(grid: List[List[Int]]): List[(Int, Int, Set[Int])] =
      for {(row, r) <- grid.zipWithIndex; 
           (col, c) <- row.zipWithIndex if (col == 0)} yield (r, c,  hyp(r, c))       
    

    以上两个产生相同的编译代码。

    请注意,您的要求意味着所有解决方案都是最小的 O(n) = O(r*c) - 您必须访问每个单元格。然而,user60561 的回答的整体行为是 O(n^2) = O((r*c)^2):对于每个单元格,在 list(x)(y) 中有一个 O(n) 查找:

    for{ x <- list.indices
         y <- list(0).indices
         if list(x)(y) == 0 } yield (x, y, hyp(x, y))
    

    这里有类似的(命令式!)逻辑,但是 O(n):

    var r, c = -1
    for{ row <- list; col <- row if col == 0} yield {
      r += 1
      c += 1
      (r, c, hyp(r, c))
    }
    

    递归版本(使用结果累加器来启用尾递归):

    type Grid = List[List[Int]]
    type GridHyp = List[(Int, Int, Set[Int])]
    
    def all(grid: Grid): GridHyp = {
      def rowHypIter(row: List[Int], r: Int, c: Int, accum: GridHyp) = row match {
        case Nil => accum
        case col :: othCols => rowHypIter(othCols, r, c + 1, hyp(r, c) :: accum)}
      def gridHypIter(grid: Grid, r: Int, accum: GridHyp) = grid match {
        case Nil => accum
        case row :: othRows => gridHypIter(othRows, r + 1, rowHyp(row, r, 0, accum))}
      gridHypIter(grid, 0, Nil)
    }
    

    'Monadic' 逻辑(flatmap/map/withFilter 或等效的理解)通常/通常比递归 + 模式匹配更简洁 - 在这里很明显。

    【讨论】:

    • 因为理解不是循环——它们纯粹是 flatmap/map/withFilter 的语法糖。但也许你不能使用它们?
    • 我不能使用迭代,我必须使用递归,在这种情况下理解好吗?
    • 好的。但这与您提出的问题不同。已添加到我的 A 中。
    • 我不明白,但非常感谢lotttt。我会考虑你的第一段代码,你能解释一下吗? (即 def all(grid: List[List[Int]]): List[(Int, Int, Set[Int])] = grid.zipWithIndex flatMap {case (row, r) => row.zipWithIndex.withFilter(_ ._1 == 0) 地图 {case (col, c) => (r, c, hyp(r, c))} } )
    【解决方案2】:

    我能想到的最简单的方法就是经典的for循环:

    for{ x <- list.indices
         y <- list(0).indices
         if list(x)(y) == 0 } yield (x, y, hyp(x, y))
    

    它假定您的第二个维度是统一的大小。使用此代码,如果您的网格大小大于 100 左右,我还建议您使用 Array 或 Vector,因为 list(x)(y) 是 O(n) 操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-06
      • 1970-01-01
      • 2018-03-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多