我有两个列表,比如 val l1 = List(1, 2, 3, 4)
和 val l2 = List(5, 6, 7, 8)
,我想合并和随机排列它们,使单个列表范围内的项目排序保持不变,但结果列表被洗牌了。
请让我解释并展示几个例子:
Desired - List(1, 2, 5, 6, 3, 4, 7, 8)
- 你可能会看到从 l1
保留的原始项目订单 - 在 1 之后变成 2,在 2 之后,变成 3 - 跳过来自 l2
的项目,因为我们看l1
中的元素仅相对于彼此。并且 l2
在 5 和 6 之后相同。
Desired - List(5, 6, 1, 2, 7, 8, 3, 4)
- 从 l1
和 l2
开始的元素顺序彼此相关地保留,类似于前面的示例。
错误 - List(6, 5, 1, 2, 7, 8, 3, 4)
- 6 在 5 之前,这与 l2 不同。
如此简单的 Random.shuffle(l1 ++ l2)
对我不起作用。
假设两个列表中的所有项目都是唯一的。
有没有什么优雅的方法可以做到这一点?谢谢!
答案 0 :(得分:4)
每次运行它都会得到不同但正确的结果。
import scala.util.Random
val l1 = List(1, 2, 3, 4)
val l2 = List(5, 6, 7, 8)
List.unfold((l1,l2)){
case (Nil, Nil) => None
case (Nil, hd::tl) => Some((hd, (Nil,tl)))
case (hd::tl, Nil) => Some((hd, (Nil,tl)))
case (a, b) =>
if (Random.nextBoolean()) Some((a.head, (a.tail,b)))
else Some((b.head, (a,b.tail)))
}
答案 1 :(得分:3)
递归方法是一种选择:
def randomInterleave[T](l1: List[T], l2: List[T]): List[T] = {
def loop(rem1: List[T], rem2: List[T], res: List[T]): List[T] =
(rem1, rem2) match {
case (Nil, _) | (_, Nil) =>
res.reverse ++ rem1 ++ rem2
case (hd :: tail, rest) if math.random() < 0.5 =>
loop(tail, rest, hd +: res)
case (rest, hd :: tail) =>
loop(rest, tail, hd +: res)
}
loop(l1, l2, Nil)
}
这是否优雅是一个见仁见智的问题:)
答案 2 :(得分:2)
这是一种通过尾递归的方法,通过迭代地从两个有序列表之一中随机选择一个元素来组装一个新列表:
def mergeInOrder(list1: List[Int], list2: List[Int]): List[Int] = {
@scala.annotation.tailrec
def loop(l1: List[Int], l2: List[Int], acc: List[Int]): List[Int] = (l1, l2) match {
case (Nil, Nil) => acc
case (h1::t1, Nil) => loop(t1, l2, h1::acc)
case (Nil, h2::t2) => loop(l1, t2, h2::acc)
case (h1::t1, h2::t2) =>
if (math.random < 0.5) loop(t1, l2, h1::acc) else loop(l1, t2, h2::acc)
}
loop(list1, list2, Nil).reverse
}