在Scala中以备用方式创建包含元素1和2的子列表

时间:2018-03-07 22:01:45

标签: scala list functional-programming

大家好我是Scala的新手,我有疑问:

以其他方式创建包含元素1和2的子列表,从不重复连续两个数字。

我的功能:

def functionAlternateElements(list : List[Int]): Option[List[Int]] = {
//What should be the solution?
}

测试:

test("AlternateElementsTests") {
assert(ca1.functionAlternateElements(List(1)) === Some(List(1)))
assert(ca1.functionAlternateElements(List(1,2)) === Some(List(2)))
assert(ca1.functionAlternateElements(List(1,2,3)) === Some(List(1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4)) === Some(List(1, 2, 1)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5)) === Some(List(2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6)) === Some(List(1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7)) === Some(List(1, 2, 1, 2, 1)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8)) === Some(List(2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9)) === Some(List(1, 2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10)) === Some(List(1, 2, 1, 2, 1, 2, 1)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11)) === Some(List(2, 1, 2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12)) === Some(List(1, 2, 1, 2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13)) === Some(List(1, 2, 1, 2, 1, 2, 1, 2, 1)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14)) === Some(List(2, 1, 2, 1, 2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)) === Some(List(1, 2, 1, 2, 1, 2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)) === Some(List(1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)) === Some(List(2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2)))

}

我该怎么做?

如果您知道代码可以给出解释,我可以理解吗?

1 个答案:

答案 0 :(得分:1)

鉴于断言似乎或多或少是任意的,我不知道如何编写一个可以产生这些奇怪输出的程序。

但是,我知道如何编写一个可以编写程序的程序,它可以产生这些奇怪的输出。我们的想法是生成满足要求的代码。我们将通过提供ansatz然后通过蛮力搜索一堆魔法数字来生成它。

首先,让我们构建一些基础架构。我们需要一个微小的框架来通过暴力解决任意问题。这是一个对非常小的问题有用的特性:

trait BruteForce[X] {
  def engageBruteForceAttack(constraint: X => Boolean): Option[X]
  def zip[Y](other: BruteForce[Y]): BruteForce[(X, Y)] = 
    new ProductBruteForce[X, Y](this, other)
}

我们只需处理有限情况和笛卡尔积的情况:

class FiniteBruteForce[X](possibilities: List[X])
extends BruteForce[X] {
  def engageBruteForceAttack(constraint: X => Boolean) = possibilities.find(constraint)
}

object FiniteBruteForce {
  def apply[X](xs: X*) = new FiniteBruteForce[X](xs.toList)
}

class ProductBruteForce[A, B](a: BruteForce[A], b: BruteForce[B])
extends BruteForce[(A, B)] {
  def engageBruteForceAttack(constraint: ((A, B)) => Boolean) = {
    var solution: Option[(A, B)] = None
    a.engageBruteForceAttack { x => 
      b.engageBruteForceAttack { y => 
        if (constraint((x, y))) {
          solution = Some((x, y))
          true
        } else {
          false
        }
      }.map(_ => true).getOrElse(false)
    }
    solution
  }
}

现在我们可以从您的测试用例中提取输入和输出:

val mysteriousTestCases = List(
  (List(1), List(1)),
  (List(1,2), List(2)),
  (List(1,2,3), List(1, 2)),
  (List(1,2,3,4), List(1, 2, 1)),
  (List(1,2,3,4,5), List(2, 1, 2)),
  (List(1,2,3,4,5,6), List(1, 2, 1, 2)),
  (List(1,2,3,4,5,6,7), List(1, 2, 1, 2, 1)),
  (List(1,2,3,4,5,6,7,8), List(2, 1, 2, 1, 2)),
  (List(1,2,3,4,5,6,7,8,9), List(1, 2, 1, 2, 1, 2)),
  (List(1,2,3,4,5,6,7,8,9,10), List(1, 2, 1, 2, 1, 2, 1)),
  (List(1,2,3,4,5,6,7,8,9,10,11), List(2, 1, 2, 1, 2, 1, 2)),
  (List(1,2,3,4,5,6,7,8,9,10,11,12), List(1, 2, 1, 2, 1, 2, 1, 2)),
  (List(1,2,3,4,5,6,7,8,9,10,11,12,13), List(1, 2, 1, 2, 1, 2, 1, 2, 1)),
  (List(1,2,3,4,5,6,7,8,9,10,11,12,13,14), List(2, 1, 2, 1, 2, 1, 2, 1, 2)),
  (List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), List(1, 2, 1, 2, 1, 2, 1, 2, 1, 2)),
  (List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), List(1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1)),
  (List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17), List(2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2))
)

现在让我们编写一个程序,它将为我们编写计算奇怪的1,2,1,1,2,......序列的函数:

val (illuminatiPivot, (illuminatiOffset, illuminatiShift)) = 
  FiniteBruteForce(-1, -2, 0, 1, 2).zip(
    FiniteBruteForce(-1, -2, 1, 2, 3).zip(
      FiniteBruteForce(0, 1, 2)
    )
  ).engageBruteForceAttack{ case (p, (o, s)) => 
    mysteriousTestCases.forall { case (input, output) =>
      val (start :: tail) = output
      val n = input.size
      val illuminatiNumber = 
        if (n < p) (n + o) 
        else List(1, 1, 2)((n + s) % 3)

      start == illuminatiNumber
    }
  }.get

println(s"""|// The function that generates the start number
            |// of the strange sequences
            |def illuminatiNumber(n: Int): Int = {
            |  if (n < $illuminatiPivot) (n + $illuminatiOffset)
            |  else List(1, 1, 2)((n + $illuminatiShift) % 3)
            |}
            |""".stripMargin)

现在对输出的长度做同样的事情。这是ansatz:它应该是一些仿射线性函数,它以2/3因子增长并以奇怪的方式舍入:

val (hl3ConfirmedConst, hl3ConfirmedOffset) = 
  FiniteBruteForce(-2, -1, 0, 1, 2).zip(
    FiniteBruteForce(-2, -1, 0, 1, 2, 3)
  ).engageBruteForceAttack{ case (c, o) => 
    mysteriousTestCases.forall { case (input, output) =>
      val n = input.size
      val halfLife3Confirmed = c + (n * 2 + o) / 3
      output.size == halfLife3Confirmed
    }
  }.get

println(s"""|def halfLife3Confirmed(i: Int): Int = {
            |  $hl3ConfirmedConst + (i * 2 + $hl3ConfirmedOffset) / 3
            |}
            |""".stripMargin)

最后,我没有费心思考如何将1映射到序列1,2,1,2,...22,1,2,1,...,所以我也粗暴地强迫它:

val (tabulationOffset, tabulationShift) = 
  FiniteBruteForce(-1, 0, 1, 2).zip(FiniteBruteForce(0, 1)).engageBruteForceAttack{
    case (x, y) =>

    (0 to 2).map(i => x + (y + 1 + i) % 2).toList == List(1, 2, 1) &&
    (0 to 2).map(i => x + (y + 2 + i) % 2).toList == List(2, 1, 2)
  }.get

现在我们可以写出最初寻找的functionAlternateElements - 方法:

println(s"""|def functionAlternateElements(list : List[Int]): Option[List[Int]] = {
            |  val n = list.size // throw away everything but the size
            |  val resultStart = illuminatiNumber(n)
            |  val resultSize = halfLife3Confirmed(n)
            |  Some(List.tabulate(resultSize){ i => $tabulationOffset + ($tabulationShift + resultStart + i) % 2 })
            |}
            |""".stripMargin)

让我们再次写出断言:

for ((i, o) <- mysteriousTestCases) {
  val input = i.mkString("List(", ",", ")")
  val output = o.mkString("List(", ",", ")")
  println(s"""assert(functionAlternateElements($input) == Some($output))""")
}

而且让我们添加一条线告诉我们最终一切顺利:

println("""println("All assertions are true")""")

运行时,上述装置产生以下代码:

// The function that generates the start number
// of the strange sequences
def illuminatiNumber(n: Int): Int = {
  if (n < -1) (n + -1)
  else List(1, 1, 2)((n + 0) % 3)
}

def halfLife3Confirmed(i: Int): Int = {
  0 + (i * 2 + 1) / 3
}

def functionAlternateElements(list : List[Int]): Option[List[Int]] = {
  val n = list.size // throw away everything but the size
  val resultStart = illuminatiNumber(n)
  val resultSize = halfLife3Confirmed(n)
  Some(List.tabulate(resultSize){ i => 1 + (1 + resultStart + i) % 2 })
}

assert(functionAlternateElements(List(1)) == Some(List(1)))
assert(functionAlternateElements(List(1,2)) == Some(List(2)))
assert(functionAlternateElements(List(1,2,3)) == Some(List(1,2)))
assert(functionAlternateElements(List(1,2,3,4)) == Some(List(1,2,1)))
assert(functionAlternateElements(List(1,2,3,4,5)) == Some(List(2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6)) == Some(List(1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7)) == Some(List(1,2,1,2,1)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8)) == Some(List(2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9)) == Some(List(1,2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10)) == Some(List(1,2,1,2,1,2,1)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11)) == Some(List(2,1,2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12)) == Some(List(1,2,1,2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13)) == Some(List(1,2,1,2,1,2,1,2,1)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14)) == Some(List(2,1,2,1,2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)) == Some(List(1,2,1,2,1,2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)) == Some(List(1,2,1,2,1,2,1,2,1,2,1)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)) == Some(List(2,1,2,1,2,1,2,1,2,1,2)))
println("All assertions are true")

当我们执行生成的代码时,我们只得到:

All assertions are true

并且没有AssertionErrors。因此,我们成功地实现了奇怪的功能。

当天的提示:当你满足测试的唯一方法就是通过暴力破解大量的魔术数字时,你知道你的规范很糟糕。