使用 scalacheck 生成排列
我有一些像这样的生成器:
val fooRepr = oneOf(a, b, c, d, e)
val foo = for (s <- choose(1, 5); c <- listOfN(s, fooRepr)) yield c.mkString("$")
这会导致重复...我可能会得到两个 a 等。我真正想要的是生成恰好 0 或 1 或每个 a、b、c、d 或 e 的随机排列(至少其中之一),以任何顺序。
我想一定有一个简单的方法,但我正在努力寻找一个困难的方法。 :)
编辑:好的,这似乎有效:
val foo = for (s <- choose(1, 5);
c <- permute(s, a, b, c, d, e)) yield c.mkString("$")
def permute[T](n: Int, gs: Gen[T]*): Gen[Seq[T]] = {
val perm = Random.shuffle(gs.toList)
for {
is <- pick(n, 1 until gs.size)
xs <- sequence[List,T](is.toList.map(perm(_)))
} yield xs
}
...大量借鉴 Gen.pick
。
谢谢你的帮助,-埃里克
I have some generators like this:
val fooRepr = oneOf(a, b, c, d, e)
val foo = for (s <- choose(1, 5); c <- listOfN(s, fooRepr)) yield c.mkString("$")
This leads to duplicates ... I might get two a's, etc. What I really want is to generate random permutation with exactly 0 or 1 or each of a, b, c, d, or e (with at least one of something), in any order.
I was thinking there must be an easy way, but I'm struggling to even find a hard way. :)
Edited: Ok, this seems to work:
val foo = for (s <- choose(1, 5);
c <- permute(s, a, b, c, d, e)) yield c.mkString("$")
def permute[T](n: Int, gs: Gen[T]*): Gen[Seq[T]] = {
val perm = Random.shuffle(gs.toList)
for {
is <- pick(n, 1 until gs.size)
xs <- sequence[List,T](is.toList.map(perm(_)))
} yield xs
}
...borrowing heavily from Gen.pick
.
Thanks for your help, -Eric
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Rex,感谢您准确地澄清了我想要做的事情,这是有用的代码,但对于 scalacheck 来说可能不太好,特别是如果所讨论的生成器非常复杂的话。在我的特定情况下,生成器 a、b、c 等生成巨大的字符串。
无论如何,我上面的解决方案有一个错误;对我有用的是下面的。我在 github 上放置了一个小项目来演示如何执行此操作,
其内容如下。如果有更好的方法,我很想知道......
谢谢,
埃里克
Rex, thanks for clarifying exactly what I'm trying to do, and that's useful code, but perhaps not so nice with scalacheck, particularly if the generators in question are quite complex. In my particular case the generators a, b, c, etc. are generating huge strings.
Anyhow, there was a bug in my solution above; what worked for me is below. I put a tiny project demonstrating how to do this at github
The guts of it is below. If there's a better way, I'd love to know it...
Thanks,
Eric
您不是在描述排列,而是描述幂集(减去空集)编辑:您正在描述幂集和排列的组合。索引集合 N 的幂集与 2^N 同构,因此我们简单地(仅在 Scala 中;也许您想更改它以便与 ScalaCheck 一起使用):生成给定集合的所有可能子集。当然,如果原始集合包含多个元素,则显式生成幂集是不明智的。如果您不想生成所有这些,只需传入从
1
到(1<<(xs.length-1))
的随机数并运行内循环。 (如果有 33-64 个元素,则切换到Long
;如果还有更多元素,则切换到BitSet
。)然后,如果您愿意,可以对结果进行排列以切换顺序。编辑:如果您可以轻松生成排列并且可以添加虚拟参数,那么还有另一种方法可以做到这一点:使用
Stop
标记使您的列表更长。然后排列并.takeWhile(_ != Stop)
。哒哒!任意长度的排列。 (如果需要的话,过滤掉零长度答案。)You're not describing a permutation, but the power set (minus the empty set)Edit: you're describing a combination of a power set and a permutation. The power set of an indexed set N is isomorphic to 2^N, so we simply (in Scala alone; maybe you want to alter this for use with ScalaCheck):to generate all possible subsets given a set. Of course, explicit generation of power sets is unwise if they original set contains more than a handful of elements. If you don't want to generate all of them, just pass in a random number from
1
until(1<<(xs.length-1))
and run the inner loop. (Switch toLong
if there are 33-64 elements, and toBitSet
if there are more yet.) You can then permute the result to switch the order around if you wish.Edit: there's another way to do this if you can generate permutations easily and you can add a dummy argument: make your list one longer, with a
Stop
token. Then permute and.takeWhile(_ != Stop)
. Ta-da! Permutations of arbitrary length. (Filter out the zero-length answer if need be.)