我有一些像这样的生成器:
val fooRepr = oneOf(a, b, c, d, e)
val foo = for (s <- choose(1, 5); c <- listOfN(s, fooRepr)) yield c.mkString("$")
这会导致重复...我可能会得到两个等等。我真正想要的是生成随机排列,其中包含a或b,c,d或e中的0或1或者每个(至少有一个)什么的,以任何顺序。
我在想,必须有一个简单的方法,但我很难找到一个艰难的方法。 :)
编辑:好的,这似乎有效:
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
。
感谢您的帮助,-Eric
答案 0 :(得分:3)
你没有描述一个排列,但是没有描述权力集(减去空集)编辑:你描述的是权力集和排列的组合。索引集N的幂集与2 ^ N同构,所以我们只是(仅在Scala中;也许你想改变它以用于ScalaCheck):
def powerSet[X](xs: List[X]) = {
val xis = xs.zipWithIndex
(for (j <- 1 until (1<<xs.length)) yield {
for ((x,i) <- xis if ((j & (1<<i)) != 0)) yield x
}).toList
}
生成给定集合的所有可能子集。当然,如果原始集合包含多个元素,那么显式生成幂集是不明智的。如果您不想生成所有这些,只需从1
传递一个随机数,直到(1<<(xs.length-1))
并运行内部循环。 (如果有33-64个元素,则切换到Long
,如果还有更多元素,则切换到BitSet
。)然后,您可以根据需要置换结果以切换订单。
编辑:如果您可以轻松生成排列并且可以添加伪参数,则还有另一种方法可以执行此操作:使用Stop
标记使列表更长一些。然后置换并.takeWhile(_ != Stop)
。当当!任意长度的排列。 (如果需要,过滤掉零长度答案。)
答案 1 :(得分:2)
Rex,感谢您准确说明我正在尝试做什么,这是有用的代码,但是对于scalacheck可能不太好,特别是如果有问题的生成器非常复杂。在我的特殊情况下,生成器a,b,c等正在产生巨大的字符串。
无论如何,我的解决方案中存在一个错误;对我有用的是下面。我在github
上放了一个小项目来演示如何做到这一点它的内容如下。如果有更好的方法,我很想知道...
package powerset
import org.scalacheck._
import org.scalacheck.Gen._
import org.scalacheck.Gen
import scala.util.Random
object PowersetPermutations extends Properties("PowersetPermutations") {
def a: Gen[String] = value("a")
def b: Gen[String] = value("b")
def c: Gen[String] = value("c")
def d: Gen[String] = value("d")
def e: Gen[String] = value("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, 0 until gs.size)
xs <- sequence[List, T](is.toList.map(perm(_)))
} yield xs
}
implicit def arbString: Arbitrary[String] = Arbitrary(foo)
property("powerset") = Prop.forAll {
a: String => println(a); true
}
}
谢谢, 埃里克