Different Ways to Initialize a Dictionary in Swift

Different ways to initialize a dictionary in Swift?

All you're doing is noticing that you can:

  • Use explicit variable typing, or let Swift infer the type of the variable based on the value assigned to it.

  • Use the formal specified generic struct notation Dictionary<String,Double>, or use the built-in "syntactic sugar" for describing a dictionary type [String:Double].

Two times two is four.

And then there are in fact some possibilities you've omitted; for example, you could say

var dict5 : [String:Double] = [String:Double]()

And of course in real life you are liable to do none of these things, but just assign an actual dictionary to your variable:

var dict6 = ["howdy":1.0]

Different ways to declare a dictionary in Swift?

They both do the same thing to declare and initialize an empty dictionary of that key and value type.

Apple documents the first way in their Swift Guide. (Scroll down to Dictionaries section).

The second way you show is simply more formal, which may help those new to Swift who don’t know the dictionary shorthand/literal syntax.

The

Swift: declare an empty dictionary

var emptyDictionary = [String: String]()


var populatedDictionary = ["key1": "value1", "key2": "value2"]

Note: if you're planning to change the contents of the dictionary over time then declare it as a variable (var). You can declare an empty dictionary as a constant (let) but it would be pointless if you have the intention of changing it because constant values can't be changed after initialization.

Is it possible to initialize a structure with a dictionary in Swift?

Try to make suitable init() as Martin says for your structure and use it according to your requirement:

struct Book {
var title: String
var description: String
var price: Int
}

extension Book {
init(book : Dictionary<String,Any>){
title = book["Title"] as? String ?? ""
description = book["Description"] as? String ?? ""
price = book["Price"] as? Int ?? 0
}
}

let dict = ["Title": "Harry Poter", "Description": "Fantasy Novel", "Price": 190] as [String : Any]
var book: Book? = Book(book: dict)
print(book!)

Initialize dictionary from transforming an array

Dictionary's sequence initialiser

In Swift 4, assuming that the keys are guaranteed to be unique, you can simply say:

let array = [MyStruct(key: 0, value: "a"), MyStruct(key: 1, value: "b")]

let dict = Dictionary(uniqueKeysWithValues: array.lazy.map { ($0.key, $0.value) })

print(dict) // [0: "a", 1: "c"]

This is using the init(uniqueKeysWithValues:) initialiser from SE-0165. It expects a sequence of key-value tuples, where the keys are guaranteed to be unique (you'll get a fatal error if they aren't). So in this case, we're applying a lazy transform to the elements in your array in order to get a lazy collection of key-value pairs.

If the keys aren't guaranteed to be unique, you'll need some way of deciding which of the possible values to use for the given key. To do this, you can use the init(_:uniquingKeysWith:) initialiser from the same proposal, and pass a given function to determine which value to use for a given key upon a duplicate key arising.

The first argument to the uniquingKeysWith: function is the value that's already in the dictionary, the second is the value attempting to be inserted.

For example, here we're overwriting the value each time a duplicate key occurs in the sequence:

let array = [MyStruct(key: 0, value: "a"), MyStruct(key: 0, value: "b"),
MyStruct(key: 1, value: "c")]

let keyValues = array.lazy.map { ($0.key, $0.value) }
let dict = Dictionary(keyValues, uniquingKeysWith: { _, latest in latest })

print(dict) // [0: "b", 1: "c"]

To keep the first value for a given key, and ignore any subsequent values for the same key, you'd want a uniquingKeysWith: closure of { first, _ in first }, giving a result of [0: "a", 1: "c"] in this case.


Reduce with an inout accumulator

Another possible option in Swift 4, assuming you wish to merge any duplicate keys by overwriting the value at each occurrence of the given key is to use reduce(into:_:), introduced in SE-0171.

Unlike reduce(_:_:), this method uses an inout parameter for the accumulator in the combination function. This allows it to avoid the unnecessary copying of the accumulator that would otherwise occur at each iteration of reduce(_:_:) when populating a dictionary accumulator. This therefore allows us to populate it in linear, rather than quadratic time.

You can use it like so:

let array = [MyStruct(key: 0, value: "a"), MyStruct(key: 0, value: "b"),
MyStruct(key: 1, value: "c")]

let dict = array.reduce(into: [:]) { $0[$1.key] = $1.value }

print(dict) // [0: "b", 1: "c"]


// with initial capacity to avoid resizing upon populating.
let dict2 = array.reduce(into: Dictionary(minimumCapacity: array.count)) { dict, element in
dict[element.key] = element.value
}

print(dict2) // [0: "b", 1: "c"]

How to initialize an array inside a dictionary?

I think you could be misunderstanding something pretty key - let's make sure:

The way the dictionary works, is not to have one array, but an array for each key.

Each value of 'idx' you request the array for returns a different array.

You can't expect it to return an empty array - a dictionary is meant to return a nil value for a key that hasn't been set. To do what you're trying, the following would probably do the trick:

myDict[idx] = myDict[idx] ?? []

Dictionary in Swift

In Swift, you can declare and initialize an empty Dictionary with type String for keys and type Any for values in 4 different ways:

  1. var myDic1 = [String : Any]()
  2. var myDic2 = Dictionary<String, Any>()
  3. var myDic3: [String : Any] = [:]
  4. var myDic4: Dictionary<String, Any> = [:]

These will all give you the same result which is an empty Dictionary with Strings as the keys and Anys as the values.

[String : Any] is just shorthand for Dictionary<String, Any>. They mean the same thing but the shorthand notation is preferred.

In cases 1 and 2 above, the types of the variables are inferred by Swift from the values being assigned to them. In cases 3 and 4 above, the types are explicitly assigned to the variables, and then they are initialized with an empty dictionary [:].

When you create a dictionary like this:

var myDic5 = [:]

Swift has nothing to go on, and it gives the error:

Empty collection literal requires an explicit type

Historical Note: In older versions of Swift, it inferred [:] to be of type NSDictionary. The problem was that NSDictionary is an immutable type (you can't change it). The mutable equivalent is an NSMutableDictionary, so these would work:

var myDic6: NSMutableDictionary = [:]

or

var myDic7 = NSMutableDictionary()

but you should prefer using cases 1 or 3 above since NSMutableDictionary isn't a Swift type but instead comes from the Foundation framework. In fact, the only reason you were ever able to do var myDic = [:] is because you had imported the Foundation framework (with import UIKit, import Cocoa, or import Foundation). Without importing Foundation, this was an error.

Initialising empty arrays of dictionaries in Swift

You need to give types to the dictionaries:

var myNewDictArray: [Dictionary<String, Int>] = []

or

var myNewDictArray = [Dictionary<String, Int>]()

Edit: You can also use the shorter syntax:

var myNewDictArray: [[String:Int]] = []

or

var myNewDictArray = [[String:Int]]()


Related Topics



Leave a reply



Submit