Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
130 views
in Technique[技术] by (71.8m points)

scala - generate list of case class with int field without repeat

I want to generate a List of some class which contains several fields. One of them is Int type and it doesn’t have to repeat. Could you help me to write the code?

I tried next:

  case class Person(name: String, age: Int)

  implicit val genPerson: Gen[Person] = 
    for {
    name <- arbitrary[String]
    age <- Gen.posNum[Int]
    } yield Person(name, age)

  implicit val genListOfPerson: Gen[scala.List[Person]] = Gen.listOfN(3, genPerson)

The problem is that I got an instance of a person with equal age.

question from:https://stackoverflow.com/questions/65845236/generate-list-of-case-class-with-int-field-without-repeat

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you're requiring that no two Persons in the generated list have the same age, you can

implicit def IntsArb: Arbitrary[Int] = Arbitrary(Gen.choose[Int](0, Int.MaxValue))
implicit val StringArb: Arbitrary[String] = Arbitrary(Gen.listOfN(5, Gen.alphaChar).map(_.mkString))
implicit val PersonGen = Arbitrary(Gen.resultOf(Person.apply _))
implicit val PersonsGen: Arbitrary[List[Person]] =
  Arbitrary(Gen.listOfN(3, PersonGen.arbitrary).map { persons =>
    val grouped: Map[Int, List[Person]] = persons.groupBy(_.age)
    grouped.values.map(_.head) // safe because groupBy
  })

Note that this will return a List with no duplicate ages but there's no guarantee that the list will have size 3 (it is guaranteed that the list will be nonempty, with size at most 3).

If having a list of size 3 is important, at the risk of generation failing if the "dice are against you", you can have something like:

def uniqueAges(persons: List[Person], target: Int): Gen[List[Person]] = {
  val grouped: Map[Int, List[Person]] = persons.groupBy(_.age)
  val uniquelyAged = grouped.values.map(_.head)
  val n = uniquelyAged.size
  if (n == target) Gen.const(uniquelyAged)
  else {
    val existingAges = grouped.keySet
    val genPerson = PersonGen.arbitrary.retryUntil { p => !existingAges(p.age) }
    Gen.listOf(target - n, genPerson)
      .flatMap(l => uniqueAges(l, target - n))
      .map(_ ++ uniquelyAged)
  }
}

implicit val PersonsGen: Arbitrary[List[Person]] =
  Arbitrary(Gen.listOfN(3, PersonGen.arbitrary).flatMap(l => uniqueAges(l, 3)))

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...