生成带有 int 字段的案例 class 列表而不重复

generate list of case class with int field without repeat

我想生成一些 class 的列表,其中包含多个字段。其中一个是Int类型,不用重复。你能帮我写代码吗?

接下来我尝试了:

  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)

问题是我得到了一个年龄相同的人的实例。

您可以按照以下方式进行:

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))

如果您要求生成的列表中没有两个 Person 年龄相同,您可以

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
  })

请注意,这将 return 一个没有重复年龄的 List,但不能保证列表的大小为 3(保证列表为非空,最大为3).

如果有一个大小为 3 的列表很重要,如果“骰子对你不利”则有生成失败的风险,你可以有类似的东西:

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)))