我搜索最佳和最优雅的方法,使Scala功能中的GA交叉运算符(No“for”循环,如果可能,只有不可变类型),例如,使用此列表:
val A = IndexedSeq (5,4,8)
val B = IndexedSeq (3,2,6)
我想在我的IndexedSeq中的每个元素之间进行随机比特币排列(例如rng.nextBoolean
),最后在元素排列后得到两个列表A'和B'。
执行示例:
rng.nextBoolean <- (true,false,true)
A' = 3,4,6
B' = 5,2,8
感谢。
答案 0 :(得分:4)
def crossover[T](a: Seq[T], b: Seq[T], rs: Seq[Boolean]) =
(a, b, rs).zipped.map((x, y, z) => if (z) Seq(x, y) else Seq(y, x)).transpose
与布尔值一起使用作为第三个参数:
scala> val Seq(a1, b1) = crossover(A, B, List(true, false, true))
a1: Seq[Int] = Vector(5, 2, 8)
b1: Seq[Int] = Vector(3, 4, 6)
如果您希望它具有默认的布尔序列,您可以提供如下默认参数:
def crossover[T](a: Seq[T], b: Seq[T], rs: Seq[Boolean] = {
val rng = new util.Random
Stream.continually(rng.nextBoolean) }) =
(a, b, rs).zipped.map((x, y, z) => if (z) Seq(x, y) else Seq(y, x)).transpose
答案 1 :(得分:4)
val (a1, b1) = A zip B map (t => if (util.Random.nextBoolean) t.swap else t) unzip
那就是全部。
如果您已经有一个随机布尔列表,您可以这样做:
val (a1, b1) = A zip B zip C map { case (t, flag) => if (flag) t.swap else t } unzip
答案 2 :(得分:1)
import scala.util.Random
val A = IndexedSeq(5,4,8)
val B = IndexedSeq(3,2,6)
def crossover[T](rng: Random)(a: Seq[T], b: Seq[T]): (Seq[T],Seq[T]) = {
if (a.isEmpty && b.isEmpty) return (Nil,Nil)
val (aTailCrossover,bTailCrossover) = crossover(rng)(a.tail,b.tail)
if (rng.nextBoolean) (b.head +: aTailCrossover, a.head +: bTailCrossover)
else (a.head +: aTailCrossover, b.head +: bTailCrossover)
}
println(crossover(new Random)(A,B))
答案 3 :(得分:0)
def rndCombi [T] (a: Seq[T], b: Seq[T]): Seq[T] = {
if (a.size != b.size) sys.error ("sizes don't match: a:" + a.size + " != b: " + b.size)
val rnd = util.Random
val max = (math.pow (2, a.size)).toInt
val r = rnd.nextInt (max)
def pick (a: Seq[T], b: Seq[T], r: Int) : List[T] = {
if (a.size == 0) Nil else
if (r % 2 == 0) a.head :: pick (a.tail , b.tail, r/2) else
b.head :: pick (a.tail , b.tail, r/2)
}
// print all combinations for testing:
// (0 until max).map (i => println (pick (a, b, i).mkString ("-")))
pick (a, b, r).toSeq
}
// I choosed different values for easy testing:
val a = IndexedSeq (7, 8, 9)
val b = IndexedSeq (1, 2, 3)
println (rndCombi (a, b).mkString (" "))
println (rndCombi (a, b.tail).mkString (" "))
如果频繁完成,每次初始化util.Random当然不是很聪明。因此,对于生产代码,您将重新排列代码。
如果不将输入限制为2个序列,则会更有趣。我们走了:
def rndCombi [T] (s: Seq[Seq[T]]): Seq[T] = {
val outer = s.size
val inner = s(0).size
val rnd = util.Random
val max = (math.pow (outer, inner)).toInt
val r = rnd.nextInt (max)
def pick (s: Seq[Seq[T]], r: Int, pos: Int = 0) : List[T] =
if (pos == inner) Nil
else s(r % inner)(pos) :: pick (s, r/inner, pos + 1)
// print all combinations for testing:
(0 until max).map (i => println (pick (s, i).mkString ("-")))
println ()
pick (s, r).toSeq
}
val a = IndexedSeq (1, 2, 3)
val b = IndexedSeq (4, 5, 6)
val c = IndexedSeq (7, 8, 9)
println (rndCombi (Seq (a, b, c)).mkString (" "))
第二种解决方案当然也可用于2个序列。