Scala for / yield运行但未完成

时间:2017-03-10 18:03:54

标签: scala

我正在尝试遍历两个可能不同大小的数组,并从中构建一个随机选择的元素的新数组(用于遗传算法中的交叉)(childGeneCount只是较长数组的长度)。

在下面的代码片段中,每个gene.toString都会记录,但我的代码似乎没有执行最后一个日志。我在做什么蠢事?

val genes = for (i <- 0 to childGeneCount) yield {
  val gene = if (Random.nextBoolean()) {
    if (i < p1genes.length) {
      p1genes(i)
    } else {
      p2genes(i)
    }
  } else {
    if (i < p2genes.length) {
      p2genes(i)
    } else {
      p1genes(i)
    }
  }
  Logger.debug(gene.toString)
  gene
}
Logger.debug("crossover finishing - never gets here??")

scala的新手,如果合适的话,他会很高兴手腕上的一记耳光伴随着“以完全不同的方式做”。

4 个答案:

答案 0 :(得分:2)

你是对的,问题在于&#34;到&#34;应该是&#34;直到&#34;。我已经改变了你的代码,使它更像scala。

  val p1genes = "AGTCTC"
  val p2genes = "ATG"

  val genePair = p1genes.zipAll(p2genes, None, None)
  val matchedGene = for (pair <- genePair) yield {
    pair match {
      case (p1Gene, None) => p1Gene
      case (None, p2Gene) => p2Gene
      case (p1Gene, p2Gene) => if (Random.nextBoolean()) p1Gene else p2Gene
    }
  }
  println(matchedGene)

过程是:

  1. 首先将两个dna序列压缩成一个。
  2. 使用无填充较短的序列。
  3. 现在遍历压缩序列并填充新序列。

答案 1 :(得分:2)

通过更清晰的None处理重写了Tawkir的答案:

val p1genes = "AGTCTC"
val p2genes = "ATG"

val genePair = p1genes.map(Some.apply).zipAll(p2genes.map(Some.apply), None, None)
val matchedGene = genePair.map {
  case (Some(p1Gene), None) => p1Gene
  case (None, Some(p2Gene)) => p2Gene
  case (Some(p1Gene), Some(p2Gene)) => if (Random.nextBoolean()) p1Gene else p2Gene
}
println(matchedGene)

如果你想避免用Some包裹序列,另一个解决方案是使用一个已知不会出现在序列中的字符作为&#34; none&#34;标记:

val p1genes = "AGTCTC"
val p2genes = "ATG"

val none = '-'
val genePair = p1genes.zipAll(p2genes, none, none)
val matchedGene = genePair.map {
  case (p1Gene, `none`) => p1Gene
  case (`none`, p2Gene) => p2Gene
  case (p1Gene, p2Gene) => if (Random.nextBoolean()) p1Gene else p2Gene
}
println(matchedGene)

答案 2 :(得分:1)

非常肯定harry0000的答案是正确的:我正在使用&#34;来&#34;喜欢&#34;直到&#34;,我已经习惯了被大声抛出的异常,我没想到要看那里!

我最终从for / yield切换到List.tabulate(childGeneCount){ i => {,这可能是出于同样的原因修复了错误。

答案 3 :(得分:1)

由于您要求可能的样式改进,这里有两个建议的实现。第一个不那么惯用,但性能更高。第二个更漂亮,但做了更多的工作。

  def crossover[E : ClassTag](a: Array[E], b: Array[E]): Array[E] = {
    val (larger, smaller) = if(a.length > b.length) (a, b) else (b, a)
    val result = Array.ofDim[E](larger.length)
    for(i <- smaller.indices)
      result(i) = if(Random.nextBoolean()) larger(i) else smaller(i)
    for(i <- smaller.length until larger.length)
      result(i) = larger(i)
    result
  }


  def crossoverIdiomatic[E : ClassTag](a: Array[E], b: Array[E]): Array[E] = {
    val randomPart = (a zip b).map { case (x,y) => if(Random.nextBoolean()) x else y }
    val (larger, smaller) = if(a.length > b.length) (a, b) else (b, a)
    randomPart ++ larger.drop(smaller.length)
  }

  val a = Array("1", "2", "3", "4", "5", "6")
  val b = Array("one", "two", "three", "four")

  // e.g. output: [one,2,three,4,5,6]
  println(crossover(a, b).mkString("[", ",", "]"))
  println(crossoverIdiomatic(a, b).mkString("[", ",", "]"))

请注意E : ClassTag只是为了让编译员对使用Array[E]感到满意,如果您的工作只需要Int,则可以删除所有花哨的泛型。