I have two NSCountedSets
and need to subtract them. For the sake of clarity, I am using a simple struct with one property as the objects:
struct MyStruct {
let name: String
init(_ name: String) {
self.name = name
}
}
func subtract(_ set1: NSCountedSet, _ set2: NSCountedSet) -> NSCountedSet {
var result = NSCountedSet()
for e in set1 {
let count1 = set1.count(for: e)
let count2 = set2.count(for: e)
let newCount = count1 - count2
if newCount > 0 {
for _ in 1 ... newCount {
result.add(e)
}
}
}
return result
}
let set1 = NSCountedSet(array: [MyStruct("A"), MyStruct("A"), MyStruct("A"), MyStruct("B"), MyStruct("C"), MyStruct("C")])
let set2 = NSCountedSet(array: [MyStruct("A"), MyStruct("B"), MyStruct("C")])
let set3 = subtract(set1, set2) // expected result: ["A", "A", "C"]`
print(set3.count(for: MyStruct("A"))) // observed result: 0 (expected 2)
print(set3.count(for: MyStruct("B"))) // observed result: 0 (expected 0)
print(set3.count(for: MyStruct("C"))) // observed result: 0 (expected 1)
But if I for instance use:
let set1 = NSCountedSet(array: ["A", "A", "A", "B", "C", "C"])
let set2 = NSCountedSet(array: ["A", "B", "C"])
I get the expected result.
I suspect that each MyStruct("A")
etc is actually not equal to the other ones since they are recreated. Which is what I see when I add a print
statement, count1
is always 1 and count2
is always 0
So maybe there is a way that I can count the number of MyStruct
by checking the name
property, is that possible?
If not, is there maybe any other solution?
You need to make your type conform to Hashable
to make NSCountedSet
compare its elements based on their properties.
struct MyStruct: Hashable {
let name: String
init(_ name: String) {
self.name = name
}
}
There's also no need to define a subtract
method, NSCountedSet
already inherits minus
from its NSMutableSet
superclass
set1.minus(Set(_immutableCocoaSet: set2))
Be aware that minus
mutates the set it's called on in place, rather than returning a new instance.
If you want to declare a non-mutating variant of minus
without having to reimplement its logic, you can simply do that by copying the set, the calling minus
on the copy.
extension NSMutableSet {
func subtracting(_ other: NSMutableSet) -> NSMutableSet {
let copy = self.mutableCopy() as! NSMutableSet
copy.minus(.init(_immutableCocoaSet: other))
return copy
}
}
let subtracted = set1.subtracting(set2)