John M
John M

Reputation: 47

ScalaCheck generate a distinct list of values

I am fairly new to ScalaCheck and somehow I want to generate a list of distinct values (i.e. a set). With my approach the values are not unique.

val valueList: Gen[List[Int]] = Gen.ListOf(Arbitrary.arbitrary[Int])

What are the possible ways to create a list with unique values/a set? Maybe with using suchThat or distinct?

Upvotes: 1

Views: 879

Answers (2)

Jeff May
Jeff May

Reputation: 467

Following up on what Levi Ramsey said, you might want to check out https://github.com/rallyhealth/scalacheck-ops for the ability to generate sets of a specific size.

import org.scalacheck.Arbitrary.arbitrary
import org.scalacheck.Gen
import org.scalacheck.ops._

Gen.setOfN(5, arbitrary[Int]).map(_.toVector)

Upvotes: 1

Levi Ramsey
Levi Ramsey

Reputation: 20541

Crude but effective:

Gen.listOf(Arbitrary.arbitrary[Int]).map(_.toSet)

If you wanted a set of a particular size, you could do something like

def setOfN[A](n: Int, gen: Gen[A]): Gen[Set[A]] =
  Gen.listOfN(n, gen).flatMap { lst =>
    val set = lst.toSet

    if (set.size == n) Gen.const(set)
    else if (set.size > n) Gen.const(set.take(n))
    else setOfN(n - set.size, gen.retryUntil(x => !set(x))).flatMap(_ ++ set)
  }

(It's worth noting that retryUntil can be fragile, especially as n grows relative to the number of commonly generated values (e.g. for Int Scalacheck generates 0, +/- 1, etc. fairly frequently))

And of course, since there's an org.scalacheck.util.Buildable instance for Set

Gen.containerOf[Set, Int](Arbitrary.arbitrary[Int])

Upvotes: 5

Related Questions