I want to be able to check that collection a
contains exactly all of the elements of b
, but an equality based check is not sufficient; for example:
data class Person(val name: String, val age: Int)
val a = listOf(Person("Alice", 10), Person("Bob", 13))
val b = listOf(Person("Alice", 10), Person("Alice", 10))
fun main() {
println(a.containsAll(b))
}
true
Whilst this is technically true
, it's not the result I want, because a
only contains one Person("Alice", 10)
, whereas b
contains two of them.
The above example should fail, whilst the below should pass.
data class Person(val name: String, val age: Int)
val a = listOf(Person("Alice", 10), Person("Alice", 10), Person("Bob", 13))
val b = listOf(Person("Alice", 10), Person("Alice", 10))
fun main() {
println(a.containsAllExact(b))
}
Is there a way to do this?
CodePudding user response:
You could add an extension function for this, something like:
fun List<Person>.containsAllExact(list2: List<Person>): Boolean {
val occurences1 = this.groupingBy{ it }.eachCount()
val occurences2 = list2.groupingBy{ it }.eachCount()
return occurences2.all{
it.value <= occurences1.getOrDefault(it.key, 0)
}
}
CodePudding user response:
One way I can think of is to make a mutable copy of a
, and try to remove every element of b
, then check if all elements of b
can be removed:
println(
a.toMutableList().let { aCopy ->
b.all(aCopy::remove)
}
)
Or as an extension function:
fun <T> Iterable<T>.strictlyContainsAll(other: Iterable<T>) =
toMutableList().let { copy ->
other.all(copy::remove)
}
CodePudding user response:
I think this would do it
println(a.containsAll(b) && (a.size - b.size == (a-b).size))
Edit: it doesn't work because it gives false negatives also. for example with
val a = listOf(Person("Alice", 10), Person("Alice", 10), Person("Bob", 13))
val b = listOf(Person("Alice", 10))