syedfa
syedfa

Reputation: 2809

Looking to use filter method to remove duplicate model objects based on two attributes from array using Swift

I have an array of model objects that I have created from JSON data. I have thousands of records that contain duplicates, which I need to remove. A record is considered a duplicate if it has the same "name", and the same "address" attributes.

The problem is, the only way I know how to remove the duplicate objects is by performing a for loop, within a for loop search, and I'm wondering if there is not a better, more efficient way? I figure that the best approach for this would be to use the "filter" method, but I'm having difficulty configuring it to work with an array that contains model objects with multiple attributes.

My model object looks like this:

struct Person {

    let id: Int
    let name: String
    let address: String


    init(id:Int, name:String, address:String) {
        self.id = id
        self.name = name
        self.address = address
    }
}

The way I'm trying to use the filter method on my array of model objects looks like this (which I know does not work):

let uniqueArray = peopleArray.filter { $0.name == $1.name, $0.address == $1.address }

Can anyone see what it is I'm doing wrong?

Upvotes: 1

Views: 807

Answers (1)

Rashwan L
Rashwan L

Reputation: 38833

1: You need to make your struct conform to Equatable protocol

func ==(lhs: Person, rhs: Person) -> Bool {
    return lhs.name == rhs.name && lhs.address == rhs.address
}

2: You can use a set to control which objects to filter from your array but you will need to make your struct conform to Hashable protocol adding a hashValue property to it.

struct Person: Equatable, Hashable {
    let id: Int
    let name: String
    let address: String
    init(id: Int, name: String, address: String) {
        self.id = id
        self.name = name
        self.address = address
    }
    var hashValue: Int {
        return name.hashValue ^ address.hashValue
    }
}

3: Usage

let people = [Person(id: 1, name: "Name A", address: "Address A"),
              Person(id: 2, name: "Name B", address: "Address B"),
              Person(id: 2, name: "Name B", address: "Address B"),
              Person(id: 3, name: "Name C", address: "Address C")]

// Will keep the order
var set: Set<Person> = []
let orderedset = people.filter{ set.insert($0).inserted }
print(orderedset)

// Will not keep the order
let unique = Set<Person>(people)
print(unique)

Tip:

If the ID is unique you should use it for comparison instead.

Upvotes: 7

Related Questions