Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Swift can I use a tuple as the key in a dictionary?

I'm wondering if I can somehow use an x, y pair as the key to my dictionary

let activeSquares = Dictionary <(x: Int, y: Int), SKShapeNode>()

But I get the error:

Cannot convert the expression's type '<<error type>>' to type '$T1'

and the error:

Type '(x: Int, y: Int)?' does not conform to protocol 'Hashable'

So.. how can we make it conform?

like image 222
JuJoDi Avatar asked Jun 10 '14 00:06

JuJoDi


People also ask

Can a tuple be used as dictionary key?

A tuple containing a list cannot be used as a key in a dictionary. Answer: True. A list is mutable. Therefore, a tuple containing a list cannot be used as a key in a dictionary.

How do you use tuples in Swift?

Swift 4 also introduces Tuples type, which are used to group multiple values in a single compound Value. The values in a tuple can be of any type, and do not need to be of same type. For example, ("Tutorials Point", 123) is a tuple with two values, one of string Type, and other is integer type. It is a legal command.

What is the difference between tuple and dictionary in Swift?

A tuple can contain only the predefined number of values, in dictionary there is no such limitation. A tuple can contain different values with different datatype while a dictionary can contain only one datatype value at a time. Tuples are particularly useful for returning multiple values from a function.

Which type is defined for key in dictionary in Swift?

The Key type of the dictionary is Int , and the Value type of the dictionary is String . To create a dictionary with no key-value pairs, use an empty dictionary literal ( [:] ).


2 Answers

The definition for Dictionary is struct Dictionary<KeyType : Hashable, ValueType> : ..., i.e. the type of the key must conform to the protocol Hashable. But the language guide tells us that protocols can be adopted by classes, structs and enums, i.e. not by tuples. Therefore, tuples cannot be used as Dictionary keys.

A workaround would be defining a hashable struct type containing two Ints (or whatever you want to put in your tuple).

like image 175
Lukas Avatar answered Oct 17 '22 03:10

Lukas


As mentioned in the answer above, it is not possible. But you can wrap tuple into generic structure with Hashable protocol as a workaround:

struct Two<T:Hashable,U:Hashable> : Hashable {
  let values : (T, U)

  var hashValue : Int {
      get {
          let (a,b) = values
          return a.hashValue &* 31 &+ b.hashValue
      }
  }
}

// comparison function for conforming to Equatable protocol
func ==<T:Hashable,U:Hashable>(lhs: Two<T,U>, rhs: Two<T,U>) -> Bool {
  return lhs.values == rhs.values
}

// usage:
let pair = Two(values:("C","D"))
var pairMap = Dictionary<Two<String,String>,String>()
pairMap[pair] = "A"
like image 20
Marek Gregor Avatar answered Oct 17 '22 03:10

Marek Gregor