6

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?

Sebastian Boldt
  • 5,283
  • 9
  • 52
  • 64
  • 5
    `Object` must conform to `Hashable`, not just `Equatable`. – Rob Napier Aug 30 '16 at 14:46
  • Possible duplicate of [Reduce array to set in Swift](http://stackoverflow.com/questions/34161786/reduce-array-to-set-in-swift) – EmilioPelaez Aug 30 '16 at 14:47
  • It is not a duplicate, I am explicitly asking about the kind of protocol I need to implement. The referenced Thread says nothing about the Hashable Protocol and consists of constructs using reduce which could lead the developer to the wrong solution. This Post is more precise and should not be marked as a duplicate to help other stack overflow users finding a solution for their problem faster. – Sebastian Boldt Aug 31 '16 at 19:56

1 Answers1

10

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 confirm 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
hnh
  • 13,957
  • 6
  • 30
  • 40