我正在尝试遍历两个可能不同大小的数组,并从中构建一个随机选择的元素的新数组(用于遗传算法中的交叉)(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的新手,如果合适的话,他会很高兴手腕上的一记耳光伴随着“以完全不同的方式做”。
答案 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 :(得分: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
,则可以删除所有花哨的泛型。