9

I'm trying to do the following code that transforms an array of tuples into a dictionary but I'm receiving a compile error saying:

Immutable value of type '[String : String]' only has mutating members named 'updateValue'

var array = [("key0", "value0"), ("key1", "value1")]
var initial = [String: String]()
var final = array.reduce(initial) { (dictionary, tuple) in
    dictionary.updateValue(tuple.0, forKey: tuple.1)
    return dictionary
}

Why is that if initial was declared as var? Does it have to do with @noescape on reduce's signature?

func reduce<U>(initial: U, combine: @noescape (U, T) -> U) -> U
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Raphael Oliveira
  • 7,751
  • 5
  • 47
  • 55

3 Answers3

9

You can simply make the dictionary parameter mutable by preceding it with var:

var final = array.reduce(initial) { (var dictionary, tuple) in
                                     ^^^

Note however that using reduce a new dictionary is created at each iteration, making the algorithm very inefficient. You might want to consider using a traditional foreach loop

Antonio
  • 71,651
  • 11
  • 148
  • 165
  • Thanks a lot! The caveat is that I can't use $0 if I want to change the mutability on those scenarios right? – Raphael Oliveira Jun 10 '15 at 15:13
  • I guess so... I am not aware of any method to make it a var (that doesn't necessarily mean it's not possible) – Antonio Jun 10 '15 at 15:20
  • @RaphaelOliveira: Part of [this answer](http://stackoverflow.com/a/24219069/1187415) is a Dictionary init method which takes an array of key/value tuples (and that uses a simple loop as well). – Martin R Jun 10 '15 at 15:34
  • I doubt performance is an issue unless you're going to `reduce` it many times/second, in which case a `[(String, String)]` probably isn't a good choice anyway – Andreas Jul 21 '15 at 23:53
  • 10
    Downvote as in Swift 2.2 (Xcode 7.3) this produces an error stating `'var' parameters are deprecated and will be removed in Swift 3`. – Robert Atkins Mar 31 '16 at 10:51
7

Swift 4 has a new variant:

var array = [("key0", "value0"), ("key1", "value1")]
var initial = [String: String]()
var final = array.reduce(into: initial) { dictionary, tuple in
    dictionary[tuple.0] = tuple.1
}

Which could be expressed:

var array = [("key0", "value0"), ("key1", "value1")]
let final: [String: String] = array.reduce(into: [:]){ $0[$1.0] = $1.1 }
mxcl
  • 26,392
  • 12
  • 99
  • 98
4

On Swift 3:

var final = array.reduce(initial) { (dictionary, tuple) -> [String: String] in
    var mutableDictionary = dictionary
    //.... make changes with mutableDictionary
    return mutableDictionary
}
Igor
  • 12,165
  • 4
  • 57
  • 73