Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unique Objects inside a Array Swift

Tags:

arrays

ios

swift

I have an array, with custom objects.

I Would like to pop the repeated objects, with the repeated properties:

let product = Product()
product.subCategory = "one"

let product2 = Product()
product2.subCategory = "two"

let product3 = Product()
product3.subCategory = "two"

let array = [product,product2,product3]

in this case, pop the product2 or product3

like image 856
Vinícius Albino Avatar asked Nov 22 '15 22:11

Vinícius Albino


People also ask

How do you make an array unique in Swift?

Use a dictionary like var unique = [<yourtype>:Bool]() and fill in the values like unique[<array value>] = true in a loop. Now unique.

What is reduce in Swift?

reduce(_:_:) Returns the result of combining the elements of the sequence using the given closure.


3 Answers

Here is an Array extension to return the unique list of objects based on a given key:

extension Array {
    func unique<T:Hashable>(map: ((Element) -> (T)))  -> [Element] {
        var set = Set<T>() //the unique list kept in a Set for fast retrieval
        var arrayOrdered = [Element]() //keeping the unique list of elements but ordered
        for value in self {
            if !set.contains(map(value)) {
                set.insert(map(value))
                arrayOrdered.append(value)
            }
        }

        return arrayOrdered
    }
}

using this you can so this

let unique = [product,product2,product3].unique{$0.subCategory}

this has the advantage of not requiring the Hashable and being able to return an unique list based on any field or combination

like image 183
Ciprian Rarau Avatar answered Sep 24 '22 06:09

Ciprian Rarau


Here is a KeyPath based version of the Ciprian Rarau' solution

extension Array {
    func unique<T: Hashable>(by keyPath: KeyPath<Element, T>) -> [Element] {
        var set = Set<T>()
        return self.reduce(into: [Element]()) { result, value in
            guard !set.contains(value[keyPath: keyPath]) else {
                return
            }
            set.insert(value[keyPath: keyPath])
            result.append(value)
        }
    }
}

example usage:

let unique = [product, product2, product3].unique(by: \.subCategory)
like image 26
Tomasz Pe Avatar answered Sep 24 '22 06:09

Tomasz Pe


If Product conforms to Equatable, where a product is equal based on it's subcategory (and you don't care about order), you can add the objects to a set, and take an array from that set:

let array = [product,product2,product3]
let set = NSSet(array: array)
let uniqueArray = set.allObjects

or

let array = [product,product2,product3]
let set = Set(array)
let uniqueArray = Array(set)
like image 31
JAL Avatar answered Sep 20 '22 06:09

JAL