4

How to generate a list of n unique values (Gen[List[T]]) from a set of values (not generators) using ScalaCheck? This post uses Gen[T]* instead of a set of values, and I can't seem to rewrite it to make it work.

EDIT

At @Jubobs' request I now shamefully display what I have tried so far, revealing my utter novice status at using ScalaCheck :-)

I simply tried to replace gs: Gen[T] repeated parameter to a Set in what @Eric wrote as a solution here:

def permute[T](n: Int, gs: Set[T]): Gen[Seq[T]] = {
    val perm = Random.shuffle(gs.toList)
    for {
        is <- Gen.pick(n, 1 until gs.size)
        xs <- Gen.sequence[List[T], T](is.toList.map(perm(_)))
    } yield xs
}

but is.toList.map(perm(_)) got underlined with red, with IntelliJ IDEA telling me that "You should read ScalaCheck API first before blind (although intuitive) trial and error", or maybe "Type mismatch, expected: Traversable[Gen[T]], actual List[T]", I can't remember.

I also tried several other ways, most of which I find ridiculous (and thus not worthy of posting) in hindsight, with the most naive being the using of @Eric's (otherwise useful and neat) solution as-is:

val g = for (i1 <- Gen.choose(0, myList1.length - 1); 
  i2 <- Gen.choose(0, myList2.length - 1)) 
  yield new MyObject(myList1(i1), myList2(i2))
val pleaseNoDuplicatesPlease = permute(4, g, g, g, g, g)

After some testing I saw that pleaseNoDuplicatesPlease in fact contained duplicates, at which point I weighed my options of having to read through ScalaCheck API and understand a whole lot more than I do now (which will inevitably, and gradually come), or posting my question at StackOverflow (after carefully searching whether similar questions exist).

Community
  • 1
  • 1
bugfoot
  • 667
  • 7
  • 20
  • 1
    *[...] I can't seem to rewrite it to make it work*. Edit your question and show what you've tried. – jub0bs May 06 '17 at 22:24

1 Answers1

8

Gen.pick is right up your alley:

scala> import org.scalacheck.Gen
import org.scalacheck.Gen

scala> val set = Set(1,2,3,4,5,6)
set: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 2, 3, 4)

scala> val myGen = Gen.pick(5, set).map { _.toList }
myGen: org.scalacheck.Gen[scala.collection.immutable.List[Int]] = org.scalacheck.Gen$$anon$3@78693eee

scala> myGen.sample
res0: Option[scala.collection.immutable.List[Int]] = Some(List(5, 6, 2, 3, 4))

scala> myGen.sample
res1: Option[scala.collection.immutable.List[Int] = Some(List(1, 6, 2, 3, 4))
jub0bs
  • 60,866
  • 25
  • 183
  • 186
  • 2
    There are a few more options as well: https://github.com/rickynils/scalacheck/blob/master/src/main/scala/org/scalacheck/Gen.scala#L651-L699 `oneOf` will choose 1, `someOf` will choose 0-n, `atLeastOne` will choose 1-n, and `pick` will choose whatever number you specify. – Charles May 07 '17 at 03:48
  • 1
    Thanks a lot Jubobs, it's `Gen.pick` then :-) – bugfoot May 07 '17 at 09:42