5

I have a dictionary that looks like this:

let ints: [Int: String] = [
    0: "0",
    1: "1",
    2: "2",
    3: "3",
    4: "4",
    5: "5",
    6: "6",
    7: "7",
    8: "8",
    9: "9",
    10: "A",
    11: "B",
    // etc...
]

I can look up an integer with ints[5] to get "5". How can I look up the integer from the string? I want to do something like ints.keys["5"] -> 5.

At the moment, I have just written the dictionary backwards:

let chars: [String: Int] = [
    "0": 0,
    "1": 1,
    "2": 2,
    "3": 3,
    "4": 4,
    "5": 5,
    "6": 6,
    "7": 7,
    "8": 8,
    "9": 9,
    "A": 10,
    "B": 11,
    // etc...
]

I can do chars["5"] to get 5, but this is a cumbersome solution since my dictionary is big and want to be able to change it easily if needed.

Clarification

I don't want to programmatically construct the dictionaries, but just keep one hard coded.

Community
  • 1
  • 1
twharmon
  • 4,153
  • 5
  • 22
  • 48
  • is there any reason to write them down by hand at all?? The mapping looks pretty basic. – luk2302 Dec 29 '16 at 16:57
  • I wrote it down basic to make the question easier to explain. – twharmon Dec 29 '16 at 17:00
  • well, you made it too basic. Is the mapping even invertible? Is it always a 1:1? – luk2302 Dec 29 '16 at 17:01
  • 3
    Possible duplicate of [Swift dictionary get key for value](http://stackoverflow.com/questions/27218669/swift-dictionary-get-key-for-value). – But if you do *many* lookups for the *same* dictionary then I would suggest to create a dictionary with the inverse mapping once. – Martin R Dec 29 '16 at 17:03

4 Answers4

6

You can take advantage of the fact that a Swift dictionary implements the Collection protocol, which extends the Sequence one, and use the first method which returns the first element of the sequence matching the given criteria:

extension Dictionary where Value: Equatable {
    func key(forValue value: Value) -> Key? {
        return first { $0.1 == value }?.0
    }
}

ints.key(forValue: "5")    // 5
ints.key(forValue: "99")   // nil

The above code works as a Dictionary can be assimilated to a sequence of (Key, Value) pairs. The only caveat is that in case of multiple keys matching to the same value we get only one of those keys, and it's not deterministic to say which one - although if your dictionary has a 1-on-1 mapping you don't have this problem.

Cristik
  • 30,989
  • 25
  • 91
  • 127
1

I used Martin R's link to find this solution:

let int = 11
print(chars.filter{$1 == int}.map{$0.0}[0]) // B
twharmon
  • 4,153
  • 5
  • 22
  • 48
  • 1
    If you know that the value to key mapping in your dictionary (`chars`) is bijective (one to one), you could use `first` rather that `filter`: the former will allow for early exit upon first hit (short-circuiting), whereas the `filter` will pass the full un-ordered dictionary. E.g., `print(chars.first(where: { $1 == int })?.0 ?? "No such value")`. – dfrib Dec 29 '16 at 19:27
  • Yes it is bijective. Thanks for this, it sped things up. – twharmon Dec 29 '16 at 19:36
1

Another approach is to construct the 1:1 reverse lookup programatically:

    var chars = ["a":1,"b":2,"c":3]

    var ints = [Int:String]()
    for pair in chars { ints[pair.value] = pair.key }

ints contains:

    [1:"a", 2:"b", 3:"c"]

Can be efficient if you're using it multiple times.

Andrew Kingdom
  • 188
  • 1
  • 9
0

Like @dfri mentioned, you can use the first method to get the first key for a given value:

extension Dictionary where Value: Equatable {

    func key(for value: Value) -> Key? {
        return first(where: { $1 == value })?.key
    }


}
Noah
  • 1,329
  • 11
  • 21
  • I already did add my solution to the [dupe target](http://stackoverflow.com/a/41386238/4573247), though... :) Also note that this does not, per se, get the "first" key, as dictionaries are non-ordered collections (so "first", semantically, holds no meaning here). It does get _some_ key, however, that may be the one single key with the supplied value, or just some among many keys that we first happened to stumble upon in the non-ordered collection. – dfrib Dec 29 '16 at 19:46