Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Subtracting NSCountedSets

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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)
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading