2

I have an array with Contact objects inside.

Then I have another array with Users.

class Contact: NSObject {

    var name: String?
    var phoneNumber: String?
    var phoneNumberFormatted: String?

    init(name: String, phoneNumber: String?, phoneNumberFormatted: String) {
        self.name = name
        self.phoneNumber = phoneNumber
        self.phoneNumberFormatted = phoneNumberFormatted
    }
}


 class User: NSObject {

        var name: String?
    }

How can I remove a Contact object from the [Contact] if I have a User in my [User] with a matching name?

I know how to do it through loops but what is most efficient way?

Walker
  • 1,127
  • 15
  • 39
  • A `PhoneNumber` object has a `phoneNumber` field. That doesn't make much sense, does it? – Alexander Dec 10 '16 at 00:18
  • 1
    I changed the phoneNumber objects name to Contact. Thanks for your help @AlexanderMomchliov – Walker Dec 10 '16 at 00:19
  • Does it make sense for a contact to not have a name? – Alexander Dec 10 '16 at 00:22
  • No. The contact should have a name. @AlexanderMomchliov – Walker Dec 10 '16 at 00:23
  • Then why is the name an optional? – Alexander Dec 10 '16 at 00:23
  • @AlexanderMomchliov I've always safely unwrapped my object properties. I think a better practice is to just not make things that are required optional. Thanks again man really – Walker Dec 10 '16 at 00:25
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/130265/discussion-between-alexander-momchliov-and-walker). – Alexander Dec 10 '16 at 00:25
  • 1
    @Walker Is there any reason to make it a NSObject? Otherwise you shouldn't. Also if the fields are required you should use let, make it non optional and add a required initializer for the property(ies) – Leo Dabus Dec 10 '16 at 00:53
  • No specific reason. What type of object do you think it should be? @LeoDabus Thank you! – Walker Dec 10 '16 at 00:54
  • @Walker just remove it `class Contact { let name: String let phoneNumber: String let phoneNumberFormatted: String required init(name: String, phoneNumber: String, phoneNumberFormatted: String) { self.name = name self.phoneNumber = phoneNumber self.phoneNumberFormatted = phoneNumberFormatted } } ` – Leo Dabus Dec 10 '16 at 01:16
  • 1
    If you are not going to make your class NSCoding compliant you don't need to subclass NSObject – Leo Dabus Dec 10 '16 at 01:19
  • @LeoDabus all of my model objects are NSObjects. What are the benefits vs just making them a class of their own? I'm sure I'm not benefiting from anything that making it an NSObject has to bring. Thanks – Walker Dec 10 '16 at 01:20
  • 1
    You are coding in Swift, no need to subclass NSObject unless you have a specific reason (to behave as NSObject) – Leo Dabus Dec 10 '16 at 01:24
  • 1
    If you need an instance where it is needed you can take a look at this answer http://stackoverflow.com/a/37983027/2303865 – Leo Dabus Dec 10 '16 at 01:28
  • @Walker You want to remove filter `[Contact]` array and remove objects that name is matched with `[User]` array, right? – Nirav D Dec 10 '16 at 04:41
  • @Walker Subclassing `NSObject` implicitly also acts as if you added the `@objc` attribute. It will make your class available to the Objective C runtime library, which brings many new features, but also sizeable performance decreases. Subclass it only if there's a reason. One such reason is to make a class `NSCoding` compliant, in order to use CoreData. – Alexander Dec 10 '16 at 04:43
  • If you don't have a reason to be using Objective C functionality, then avoid it. This simple model class is a prime candidate for being a struct, rather than a class – Alexander Dec 10 '16 at 04:44

1 Answers1

3

The best (most computationally efficient) way to do this for non-trivial array sizes is to precompute a set from the array you need to repeatedly search, and filter your other array, keeping elements only if they're not found in the set.

This leverages the O(1) lookup performance of Set. The algorithm as a whole is O(userPhoneNumbers.count + contacts.count)

let userPhoneNumbers = Set(users.lazy.map{ $0.phoneNumber })
let filteredContacts = self.contacts.filter{ !userPhoneNumbers.contains($0.phoneNumber) }
Alexander
  • 59,041
  • 12
  • 98
  • 151