swift

Create Set of Array in Swift


I was trying to create a set out of an array to make elements unique. I thought it would be an elegant approach to use the Set initializer to do this job. So I created an array and tried to initialize my new set using that array. But the compiler was complaining. I tried it using Integer values and it works like a charm. But with my own class it does not work. I also thought that the Equatable Protocol is the right way to go .. but as you see, it does not solve my Problem.

Consider the following Playground:

 import UIKit

internal struct Object: Equatable {
    var a: Int
}

internal func == (lhs:Object,rhs: Object) -> Bool {
    return lhs.a == rhs.a
}

let array = [Object(a:1),Object(a:1),Object(a:1),Object(a:1),Object(a:2)]

let set = Set(array) // ERROR

The Compiler is complaining with

can not invoke initializer Set<_> with argument of type [Object]

Which Protocol do I need to implement to makes things work?


Solution

  • If you 'command-click' on Set in Xcode, it takes you to the definition of the Set type. And there you go:

    /// A collection of unique `Element` instances with no defined ordering.
    public struct Set<Element : Hashable> : Hashable, CollectionType ...
    

    As mentioned by Rob, the elements need to conform to Hashable (which in turn requires Equatable).

    Adjusting your code:

    import Foundation
    
    internal struct Object: Hashable {
        var a: Int
        var hashValue: Int { return a.hash }
    }
    
    internal func == (lhs:Object,rhs: Object) -> Bool {
        return lhs.a == rhs.a
    }
    
    let array = [Object(a:1),Object(a:1),Object(a:1),Object(a:1),Object(a:2)]
    
    let set = Set(array) // SUCCESS