Nobody knows, what Person and Age is. :)
Can you transfer this example to your case?
val la = List (List (1, 2), List (3, 2), List (1, 4))
// la: List[List[Int]] = List(List(1, 2), List(3, 2), List(1, 4))
val lb = List (List (1, 2), List (3, 2), List (4, 1))
// lb: List[List[Int]] = List(List(1, 2), List(3, 2), List(4, 1))
la.groupBy (_(0)).size == la.size
// res229: Boolean = false
lb.groupBy (_(0)).size == lb.size
// res230: Boolean = true
Ok. This can be abstracted. There is List of something, and depending on a predicate of these somethings, we want to find uniqueness.
def unique [T, A] (l: List[T], f: T => A): Boolean = {
l.groupBy (element => f(element)).size == l.size
}
For my example, T is a List of Integers (the inner lists) and A is just the Attribute, of T, which is selected by a function from T to A. If we group over the result of that function, the size should be unchanged, if the attribute is unique.
unique (lb, (l:List[Int]) => l(0))
Here the function is the Indexing into the inner List of ints. Now that we know the Person/Age/Name-definitions, we can test that too:
unique (datlist, (p:Person) => p.list(0))
// res254: Boolean = false
unique (datlist, (p:Person) => p.list(1))
// res255: Boolean = true
I'm a bit unhappy, that the solution doesn't reveal, that the names are not unique, while the ages are - not that the results are bogus, but that we access it with list index, not attribute name. But maybe there is a good reason, to write it like that, which is here off topic. But as far as I can tell, a Person with the attributes initialized in a different order would make this method fail. So what we really need is a method from Person to Name, not from Person to first PersonAttribute in Person.list.
This can be tried by pattern matching, but I'm not convinced of the Person design in general. Shall people without name really be possible? Person with 2 names? Or how should this be prevented from your Design?
However, ignoring the critique of the design, we can implement a verbose solution, which handles reordered Features (what I called Attributes):
unique (datlist, (p:Person) => p.list.filter (pf=> isFeatureByName (pf, "Name")))
//res259: Boolean = false1def isFeatureByName (pf: PersonFeatures, featurename: String) = (pf, featurename) match {
case (Age (_), "Age") => true
case (Name (_), "Name") => true
case (Person (_), "Person") => true
case _ => false
}
unique (datlist, (p:Person) => p.list.filter (pf=> isFeatureByName (pf, "Age")))
// res258: Boolean = true
unique (datlist, (p:Person) => p.list.filter (pf=> isFeatureByName (pf, "Name")))
// res259: Boolean = false
But how would this work with missing features, Persons without name or age, or possibly two names, two ages? I guess it is obvious, that this design needs a rethinking.
Person,Name&Ageclasses.