List Scala使用排列列表进行均匀交叉操作的最佳方法?

List Scala使用排列列表进行均匀交叉操作的最佳方法?,list,scala,permutation,genetic-algorithm,List,Scala,Permutation,Genetic Algorithm,我搜索使Scala中的GA交叉算子功能化的最佳且最优雅的方法(无“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

我搜索使Scala中的GA交叉算子功能化的最佳且最优雅的方法(无“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
rng.nextBoolean
将布尔值用作第三个参数:

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
如果频繁地初始化util.Random,那么每次初始化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个序列

哇,这些代码是从哪里来的?在这里:

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

你说的排列是指在列表之间随机交换元素吗?你能给出一个你期望的输出的例子吗?我在更新的问题上添加了更多的信息。我喜欢你的方法,因为它将随机性具体化(更实用,无副作用)。因此,您可以选择在调用端确定随机性,或者不用担心,使用默认参数调用该方法。您使用的是哪个Scala版本?Scala 2.9.1不会编译,除非您将
crossover[t](a:Seq[t],b:Seq[t],rs:Seq[Boolean]=…)
更改为
crossover[t](a:Seq[t],b:Seq[t])(rs:Seq[Boolean]=…)
@PeterSchmitz谢谢-原来我的REPL命名空间被污染了,这就是它对我有效的原因。已经更新。默认参数比我想象的要复杂,因为你需要用
交叉(A,B)(
来调用它,这有点难看。非常感谢,这是一个很好的方法:)也感谢其他贡献者的回答!伟大的简单明了!还有一个例子,我们应该熟记scala API。
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 (" "))
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