I can find many examples of setting maximum sizes for generators, but how do I generate lists between a min and max length?
2 Answers
A neat property about generators is they are composable, so you can simply compose a generator for the length of your list with a listOfN
generator.
for {
numElems <- Gen.choose(5, 12)
elems <- Gen.listOfN(numElems, elemGenerator)
} yield elems

- 1,466
- 9
- 27
-
You know what; that's simply elegant! For some reason, the library calls for transformations when dealing with sizes, e.g.: Gen.resize(12,myGenerator) which doesn't support minimum sizes. Your example is much more flexible and instructive. – Felix Jan 16 '16 at 13:04
-
Composing generators is a switch you have to flip in your head, but once to do you realize how powerful it actually is for generating specialized objects. Glad I could help! – Asa Jan 16 '16 at 15:45
-
1Use Gen.chooseNum instead of Gen.choose because chooseNum gives more weight to test and gen the min, max and special cases like 0 (if they are in range). – Onilton Maciel Sep 23 '18 at 19:25
-
1This strikes me as incorrect: the `N` in `listOfN` is described as `Generates a list with at most the given number of elements` ...meaning regardless of if `N` was 5 or 12, you could still get a list of 3 elements. Or an empty list, for that matter. – Darren Bishop Oct 11 '21 at 16:19
-
I don’t see the same documentation. Under the hood it uses `buildableOfN` which can produce containers smaller than the specified size if the containers enforce element uniqueness like a set or a map. This is not the case for List and all the documentation I find specifies that the length of the generated list is precisely the N specified – Asa Oct 11 '21 at 16:56
-
1What docs do you see? https://javadoc.io/static/org.scalacheck/scalacheck_2.11/1.14.1/index.html#org.scalacheck.Gen$@listOfN[T](n:Int,g:org.scalacheck.Gen[T]):org.scalacheck.Gen[List[T]] Or are you merely just challenging the docs with your explanation of the inner-workings (implementation details)? – Darren Bishop May 25 '22 at 13:40
-
1As other commenters stated, the answer, despite of being upvoted, is simply incorrect. Apart from what being already mentioned - that it will choose number of elements between 0 and a random one (from `Gen.choose(5, 12)`) it will mostly never give higher numbers being biased toward lower ones (due to double randomness of first selecting an upper bound and then num of elements based on it) – IgorK Dec 21 '22 at 19:49
I am waking up ghosts here, but incase anyone comes along:
As per my comment on the accepted answer, that solution randomly decides the maximum length between 5 and 12, but the actual size of the generated list could still be 0 (zero) or anything below 5, in that case.
I think the following does what the OP describes:
Gen
.listOfN(12, elemGenerator)
.suchThat(_.size >= 5)
Would be cool if there was an API to conveniently generate this, or say a list of an exact size, N
.
Update (2022/12/22)... as I realise I never actually answered the OP's question (and prompted by a recent comment):
def listOf[E](min: Int, max: Int, factor: Int = 4, retries: Int = 10000)(implicit gen: Gen[E]): Gen[List[E]] = for {
size <- Gen.choose(min, max)
list <- Gen.listOfN(factor * size, gen).retryUntil(_.size >= min, retries).flatMap(_.take(size))
} yield list
The factor
is some attempt to increase the odds that within 10,000 tries (ScalaCheck's default), a list greater than size min
will be generated; perhaps too large a factor
will skew away from min
-sized lists.
Alternatively, if you like Cats and friends (cats-scalacheck):
def listOf[E](min: Int, max: Int)(implicit gen: Gen[E]): List[E] = for {
size <- Gen.choose(min, max)
list <- List.fill(size)(gen).sequence
} yield list
I cannot attest to what happens in cats-scalacheck; maybe they also use suchThat
or retryUntil
.

- 2,379
- 23
- 20
-
1
-
As `suchThat` is identical to `filter` I would advice trying to provide your own generator, as the previous commenter suggested. Excessive filtering on generators might result in wasted CPU time, and even lead to test failures because of inability to generate a proper value within fixed number of iterations. – IgorK Dec 21 '22 at 19:53