mrchance
mrchance

Reputation: 1175

Handling of a Dictionary Element in the context of "Array" notation

Struggling to achieve 2) below.

In the examples below, T is a concrete type. T could be String but the examples would then look even stranger.

  1. Works:

     var v = [         // v is a Dictionary with two Dictionary<String, T>.Element's
         "x": T("x"),  // Unfortunate since "x" has to be repeated    
         "y": T("y") 
     ]
    
  2. Desired syntax, intended to do the same as 1). Does not work:

     var v = [        
         { let s = "x";             // Attempting to use a closure to "inline" the local variable s
           return (s: T(name: s))   // Using a tuple to return the Dictionary<String, T>.Element
         }(),
         { let s = "y";   
           return (s: T(name: s))
         }()
     ]
    

Xcode error for 2): Heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional

  1. Trying to fix 2) with explicit types. Does not work.

     var v : Dictionary<String, T>.Element = [        
         { let s = "x";             
           return Dictionary<String, T>.Element(s: T(name: s))
         }(),
         { let s = "y";             
           return Dictionary<String, T>.Element(s: T(name: s))
         }()
     ]
    

Xcode error for 3): Dictionary of type 'Dictionary<String, T>' cannot be initialized with array literal

This "MWE" example admittedly looks weird, but I am trying to understand how, in general, it may be possible to use a Dictionary Element (Key and Value together, as a hole) as if it were (informally speaking) an element of an Array.

Upvotes: 1

Views: 263

Answers (3)

mrchance
mrchance

Reputation: 1175

Sufficient solution:

var v = Dictionary<String, T>(uniqueKeysWithValues:
     [ { let s = "x"; return (s, T(s)) }(),
       { let s = "y"; return (s, T(s)) }(),
     ]
 )

That means, that you must use explicit Dictionary constructor, using uniqueKeysWithValues

Upvotes: 0

Joakim Danielson
Joakim Danielson

Reputation: 51971

I am still not sure exactly what you want but I thought I add this solution to see if it is correct or at least something to discuss further

struct T {
    let name: String
}

extension Dictionary where Key == String, Value == T {
    init(values: Key...) {
        self = values.reduce(into: [:]) { $0[$1] = T(name: $1) }
    }
}

var dict = Dictionary(values: "x", "y")

An alternative solution when the init needs to be dynamic

extension Dictionary where Key == String, Value == T {
    init(values: Key..., construct: (Key) -> T) {
        self = values.reduce(into: [:]) { $0[$1] = construct($1) }
    }
}

var dict = Dictionary(values: "x", "y") { T(name: $0)}

Upvotes: 1

Vadim Belyaev
Vadim Belyaev

Reputation: 2859

If you have an array of keys and you want to create a dictionary out of it by mapping each key to another type, I'd suggest this way:

let keys = ["x", "y", "z"]
let dict = Dictionary(
    uniqueKeysWithValues: keys.map { key in (key, T(key)) }
)

Upvotes: 1

Related Questions