用scalacheck生成排列

时间:2011-02-24 16:13:47

标签: scala scalacheck

我有一些像这样的生成器:

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

2 个答案:

答案 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
  }
}

谢谢, 埃里克