在Scala sudoku生成器中过滤嵌套列表和列表项

时间:2017-10-09 22:01:11

标签: scala sudoku

作为数独生成器的一部分,我有一个函数用于过滤嵌套列表,以便仅返回某些索引的内部列表和这些列表中某些索引的内部列表元素。我们的想法是返回一个List [Int],它包含一个3x3平方的值,取自一个9x9数独谜题,表示为List [List [Int]],它作为函数的参数提供。

我尝试了两种方法,但未能始终如一地工作。一种方法尝试从列表中过滤掉某些子列表,然后从剩余列表中过滤掉项目。此函数完全适用于某些索引,但对于其他索引,它将从某些子列表中过滤太多或太少的索引值,但不是全部:

def getGroup(indexX: Int, indexY: Int, puzzle: List[List[Int]]): List[Int] = {
  val groupX = { //determining row coordinate
  if(indexX <= 2) 2
  else if(indexX <= 5) 5
  else 8
  }
  val groupY = { //determining column coordinate
  if(indexY <= 2) 2
  else if(indexY <= 5) 5
  else 8
  }
  // Using filter
  val subsection: List[List[Int]] = puzzle.filter(x => puzzle.indexOf(x) <= groupX && puzzle.indexOf(x) >= groupX - 2) 
  // This sometimes filters out too many or too few items
  val group: List[List[Int]] = subsection.map(x => x.filter(y => x.indexOf(y) <= groupY && x.indexOf(y) >= groupY - 2))

  val result = group.flatten
  println("subsection " + subsection)
  println("group " + group)
  result
}

以下是测试列表[List [Int]]的一些输出,打印时显示结果。我不清楚为什么从一些子列表中过滤掉不正确的索引,而不是在同一个函数调用中过滤掉所有索引。我不认为我只是选择了错误的索引,否则对于同一函数调用中的所有子列表,它应该以相同的方式不正确。

test: List[List[Int]] = List(List(0, 2, 3, 4, 5, 6, 7, 8, 9), List(1, 2, 3, 4, 5, 6, 7, 8, 9), List(2, 2, 3, 4, 5, 6, 7, 8, 9), List(3, 2, 3, 4, 5, 6, 7, 8, 9), List(4, 2, 3, 4, 5, 6, 7, 8, 9), List(5, 2, 3, 4, 5, 6, 7, 8, 9), List(6, 2, 3, 4, 5, 6, 7, 8, 9), List(7, 2, 3, 4, 5, 6, 7, 8, 9), List(8, 2, 3, 4, 5, 6, 7, 8, 9))

scala> getGroup(2,2,test)
subsection: List(List(0, 2, 3, 4, 5, 6, 7, 8, 9), List(1, 2, 3, 4, 5, 6, 7, 8, 9), List(2, 2, 3, 4, 5, 6, 7, 8, 9))
group: List(List(0, 2, 3), List(1, 2, 3), List(2, 2, 3))
res12: List[Int] = List(0, 2, 3, 1, 2, 3, 2, 2, 3) //Correct 

scala> getGroup(2,7,test)
subsection: List(List(0, 2, 3, 4, 5, 6, 7, 8, 9), List(1, 2, 3, 4, 5, 6, 7, 8, 9), List(2, 2, 3, 4, 5, 6, 7, 8, 9))
group: List(List(7, 8, 9), List(7, 8, 9), List(7, 8, 9))
res13: List[Int] = List(7, 8, 9, 7, 8, 9, 7, 8, 9) //Correct 

scala> getGroup(7,7,test)
subsection: List(List(6, 2, 3, 4, 5, 6, 7, 8, 9), List(7, 2, 3, 4, 5, 6, 7, 8, 9), List(8, 2, 3, 4, 5, 6, 7, 8, 9))
group: List(List(7, 8, 9), List(8, 9), List(7, 9)) //Missing a 7 and an 8
res14: List[Int] = List(7, 8, 9, 8, 9, 7, 9) 

scala> getGroup(4,0,test)
subsection: List(List(3, 2, 3, 4, 5, 6, 7, 8, 9), List(4, 2, 3, 4, 5, 6, 7, 8, 9), List(5, 2, 3, 4, 5, 6, 7, 8, 9))
group: List(List(3, 2, 3), List(4, 2, 3, 4), List(5, 2, 3, 5)) //Not enough values filtered out--unwanted 4 and 5
res32: List[Int] = List(3, 2, 3, 4, 2, 3, 4, 5, 2, 3, 5)

另一种方法使用for循环,它只会产生符合if条件的值:

def getGroup(indexX: Int, indexY: Int, puzzle: List[List[Int]]): List[Int] = {
         //this portion is the same as above until the for expression:
  val groupX = { //determining row coordinate
    if(indexX <= 2) 2
    else if(indexX <= 5) 5
    else 8
  }
  val groupY = { //determining column coordinate
   if(indexY <= 2) 2
   else if(indexY <= 5) 5
   else 8
 }
    // using for expression
    val group = for(
      outer <- puzzle if puzzle.indexOf(outer) <= groupX && puzzle.indexOf(outer) >= groupX - 2; 
      inner <- outer if outer.indexOf(inner) <= groupY && outer.indexOf(inner) >= groupY - 2) 
        yield inner
  group
}

我已使用此List [List [Int]]测试了此函数,其中每个列表都以其索引号开头,之后才计数:

val testGrid = List(List(0,2,3,4,5,6,7,8,9),List(1,2,3,4,5,6,7,8,9),List(2,2,3,4,5,6,7,8,9),
List(3,2,3,4,5,6,7,8,9),List(4,2,3,4,5,6,7,8,9),List(5,2,3,4,5,6,7,8,9),
List(6,2,3,4,5,6,7,8,9),List(7,2,3,4,5,6,7,8,9),List(8,2,3,4,5,6,7,8,9))

但是,输出并不总是正确的:

scala> getGroup(0, 0, testGrid)
res0: List[Int] = List(0, 2, 3, 1, 2, 3, 2, 2, 3) (correct)
scala> getGroup(3,3,testGrid)
res1: List[Int] = List(4, 5, 6, 5, 6, 4, 6) (too few)
scala> getGroup(3,7,testGrid)
res2: List[Int] = List(7, 8, 9, 7, 8, 9, 7, 8, 9) (correct)
scala> getGroup(7,7,testGrid)
res3: List[Int] = List(7, 8, 9, 8, 9, 7, 9) (too few)
scala> getGroup(7,0,testGrid)
res5: List[Int] = List(6, 2, 3, 6, 7, 2, 3, 7, 8, 2, 3, 8) (too many)

为什么我得到这个输出可能有一个明显的答案,但它已经逃脱了我。我怀疑它与内部循环有关,因为indexY低于3的所有测试都是正确的,无论indexX的值如何。

我将不胜感激任何有关这些尝试的反馈。我也很感激任何关于替代方法的想法,这种方法可以使这个功能更直观或更简洁。

1 个答案:

答案 0 :(得分:1)

您可以使用.slice按索引过滤列表的某个部分。然后.map(x => x.slice(...))对内部列表执行相同操作,最后.flattenList[List[A]]转换为List[A]。一起来:

def getGroup(indexX: Int, indexY: Int, puzzle: List[List[Int]]): List[Int] = {
  val xStart = indexX / 3 * 3
  val yStart = indexY / 3 * 3
  puzzle.slice(xStart, xStart + 3).map(row => row.slice(yStart, yStart + 3)).flatten
}