如何使用 ScalaCheck 生成打乱的序列?
How do you generate a shuffled sequence with ScalaCheck?
我一直在尝试使用 scalacheck 生成随机序列。 Scalacheck 不提供任何生成器来直接执行此操作,而且我在网上找不到任何简单的答案。经过一番思考,下面是我是如何做到的。我希望其他人能找到有用的东西。
def shuffle[T](s: Seq[T], prefix: Seq[T] = Vector()): Gen[Seq[T]] =
if (s.length == 0) Gen.const(prefix.toSeq)
else
Gen.choose(0, s.length - 1)
.flatMap { i =>
shuffle(
s.take(i) ++ s.takeRight(s.length - i - 1),
prefix :+ s(i)) }
您可以使用集合改组算法(例如 scala.util.Random 中的算法)来获得更清晰的解决方案:
/**
* This represents a potential list shuffling. It
* acts as a pure function - when applied to the
* same list it always returns the same result
*/
class Shuffling(seed: Int) {
def apply[T](xs: Seq[T]): Seq[T] = {
val r = new scala.util.Random(seed)
r.shuffle(xs)
}
}
import org.scalacheck.Arbitrary._
import org.scalacheck.Gen
val shufflingGen: Gen[Shuffling] = arbitrary[Int].map(new Shuffling(_))
上面的代码片段定义了一个 shuffling
- 一个可能的 re-ordering 列表。它还定义了一个提供任意洗牌实例的生成器。以下示例显示了如何对 re-order 整数范围进行改组:
def shuffledRange(n: Int): Gen[Seq[Int]] = {
for {
shuffling <- shufflingGen
} yield shuffling(Range(0, n))
}
以 Shuffling
class 的形式添加一层间接寻址似乎很奇怪 - 我们也可以直接在列表上应用 Random.shuffle
。这是因为除了 Scalacheck 已经在后台进行的隐式随机化之外,我们还想避免额外的随机性来源——洗牌中的随机性来源来自 scalacheck 生成器。
这样做的一个好处是生成案例的可重复性(每当 Scalacheck will support it)。
org.scalacheck.Gen.pick(n: Int, l: Iterable[T]): Gen[Seq[T]]
从 l
中随机选择 n
个不同的元素。用n = l.length
调用pick
,你会随机生成一个
我一直在尝试使用 scalacheck 生成随机序列。 Scalacheck 不提供任何生成器来直接执行此操作,而且我在网上找不到任何简单的答案。经过一番思考,下面是我是如何做到的。我希望其他人能找到有用的东西。
def shuffle[T](s: Seq[T], prefix: Seq[T] = Vector()): Gen[Seq[T]] =
if (s.length == 0) Gen.const(prefix.toSeq)
else
Gen.choose(0, s.length - 1)
.flatMap { i =>
shuffle(
s.take(i) ++ s.takeRight(s.length - i - 1),
prefix :+ s(i)) }
您可以使用集合改组算法(例如 scala.util.Random 中的算法)来获得更清晰的解决方案:
/**
* This represents a potential list shuffling. It
* acts as a pure function - when applied to the
* same list it always returns the same result
*/
class Shuffling(seed: Int) {
def apply[T](xs: Seq[T]): Seq[T] = {
val r = new scala.util.Random(seed)
r.shuffle(xs)
}
}
import org.scalacheck.Arbitrary._
import org.scalacheck.Gen
val shufflingGen: Gen[Shuffling] = arbitrary[Int].map(new Shuffling(_))
上面的代码片段定义了一个 shuffling
- 一个可能的 re-ordering 列表。它还定义了一个提供任意洗牌实例的生成器。以下示例显示了如何对 re-order 整数范围进行改组:
def shuffledRange(n: Int): Gen[Seq[Int]] = {
for {
shuffling <- shufflingGen
} yield shuffling(Range(0, n))
}
以 Shuffling
class 的形式添加一层间接寻址似乎很奇怪 - 我们也可以直接在列表上应用 Random.shuffle
。这是因为除了 Scalacheck 已经在后台进行的隐式随机化之外,我们还想避免额外的随机性来源——洗牌中的随机性来源来自 scalacheck 生成器。
这样做的一个好处是生成案例的可重复性(每当 Scalacheck will support it)。
org.scalacheck.Gen.pick(n: Int, l: Iterable[T]): Gen[Seq[T]]
从 l
中随机选择 n
个不同的元素。用n = l.length
调用pick
,你会随机生成一个