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