Say I have a dictionary of type [String : String] which I want to transform to type [String : URL]. I can use map or flatMap to transform the dictionary, but due to the failable URL(string:) initializer, my values are optional:
let source = ["google" : "http://google.com", "twitter" : "http://twitter.com"]
let result = source.flatMap { ($0, URL(string: $1)) }
This returns a value of type [(String, URL?)] and not [String : URL]. Is there a one-liner to transform this dictionary with a single method? My first thought was something like:
source.filter { $1 != nil }.flatMap { ($0, URL(string: $1)!) }
But I don't need to check if the value is nil (values will never return nil on a dictionary concrete values), I need to check if the return value of URL(string:) is nil.
I could use filter to remove the nil values, but this doesn't change the return type:
source.flatMap { ($0, URL(string: $1)) }.filter { $1 != nil }
You need to make sure you're returning tuples with only non-optional values, and since optional values themselves support flatMap you can use that to make the tuple optional as opposed to the individual value inside of it:
let source = [
"google": "http://google.com",
"twitter": "http://twitter.com",
"bad": "",
]
var dict = [String: URL]()
source.flatMap { k, v in URL(string: v).flatMap { (k, $0) } }.forEach { dict[$0.0] = $0.1 }
But since we've already expanded out the dictionary creation (I don't think there's a built-in way to create a dict from an array), you might as well do this:
var dict = [String: URL]()
source.forEach { if let u = URL(string: $1) { dict[$0] = u } }
Here are a few solutions:
//: Playground - noun: a place where people can play
import Foundation
let source = ["google": "http://google.com", "twitter": "http://twitter.com", "bad": ""]
//: The first solution takes advantage of the fact that flatMap, map and filter can all be implemented in terms of reduce.
extension Dictionary {
/// An immutable version of update. Returns a new dictionary containing self's values and the key/value passed in.
func updatedValue(_ value: Value, forKey key: Key) -> Dictionary<Key, Value> {
var result = self
result[key] = value
return result
}
}
let result = source.reduce([String: URL]()) { result, item in
guard let url = URL(string: item.value) else { return result }
return result.updatedValue(url, forKey: item.key)
}
print(result)
//: This soultion uses a custom Dictionary initializer that consums the Key/Value tuple.
extension Dictionary {
// construct a dictionary from an array of key/value pairs.
init(items: [(key: Key, value: Value)]) {
self.init()
for item in items {
self[item.key] = item.value
}
}
}
let items = source
.map { ($0, URL(string: $1)) } // convert the values into URL?s
.filter { $1 != nil } // filter out the ones that didn't convert
.map { ($0, $1!) } // force unwrap the ones that did.
let result2 = Dictionary(items: items)
print(result2)
//: This solution also uses the above initializer. Since unwrapping optional values is likely a common thing to do, this solution provides a method that takes care of the unwrapping.
protocol OptionalType {
associatedtype Wrapped
var asOptional : Wrapped? { get }
}
extension Optional : OptionalType {
var asOptional : Wrapped? {
return self
}
}
extension Dictionary where Value: OptionalType {
// Flatten [Key: Optional<Type>] to [Key: Type]
func flattenValues() -> Dictionary<Key, Value.Wrapped> {
let items = self.filter { $1.asOptional != nil }.map { ($0, $1.asOptional!) }
return Dictionary<Key, Value.Wrapped>(items: items)
}
}
let result3 = Dictionary(items: source.map { ($0, URL(string: $1)) }).flattenValues()
print(result3)
Daniel T's last solution is quite nice if you want to write it in a more functional style. I'd do it a bit differently with the primary difference being a method to turn a tuple of optionals into an optional tuple. I find that to be a generally useful transform, especially combined with flatMap.
let source = ["google" : "http://google.com", "twitter" : "http://twitter.com", "fail" : ""]
// Dictionary from array of (key, value) tuples. This really ought to be built it
extension Dictionary {
public init(_ array: [Element]) {
self.init()
array.forEach { self[$0.key] = $0.value }
}
}
//Turn a tuple of optionals into an optional tuple. Note will coerce non-optionals so works on (A, B?) or (A?, B) Usefull to have variants for 2,3,4 tuples.
func raiseOptionality<A,B>(_ tuple:(A?, B?)) -> (A, B)? {
guard let a = tuple.0, let b = tuple.1 else { return nil }
return (a,b)
}
let result = Dictionary(source.flatMap { raiseOptionality(($0, URL(string: $1))) } )
Easy as pie if you just want a good, known URL in place of the bad ones.
Use
let source = ["google" : "http://google.com", "twitter" : "http://twitter.com", "bad": ""]
let defaultURL = URL(string: "http://www.google.com")! // or whatever you want for your default URL
let result = source.flatMap { ($0, URL(string: $1) ?? defaultURL) }
Related
I'd like to convert a value I get from an API to a specific format.
[String:Any] // format received
[Int:[ContentType:Int]] // required format
ContentType is an Enum
An example of the data might look like this:
["123":["Tables":"25","Chairs":"14"]] // input
[123:[.Tables:25,.Chairs:14]] // output
I think I need to have a map within a map for this to work, but I'm struggling to work out a way forward. I may well be barking up the wrong tree entirely though. I don't really want to manually loop through and add each item one at a time; I'm looking for something more intelligent than that if possible.
enum ContentType: String {
case Tables,Chairs
}
let original_values: [String:Any]
= ["1234":["Tables":"5","Chairs":"2"]]
let values: [Int:[ContentType:Int]]
= Dictionary(uniqueKeysWithValues: original_values.map {
(
Int($0.key)!,
(($0.value as? [String:String]).map { // Error on this line - expects 1 argument but two were used
(
ContentType(rawValue: $1.key)!, // $1 is presumably wrong here?
Int($1.value)
)
}) as? [ContentType:Int]
)
})
Any ideas anybody?
I'd like to convert a value I get from an API to a specific format.
You can make your enum Decodable
enum ContentType: String, Decodable {
case tables, chairs
enum CodingKeys: String, CodingKey {
case Tables = "Tables"
case Chairs = "Chairs"
}
}
Then you can decode received Data and then compactMap it to format (Int, [ContentType: Int]). These tuples you can convert to Dictionary using designed initializer
do {
let decoded = try JSONDecoder().decode([String: [ContentType: Int]].self, from: data)
let mapped = Dictionary(uniqueKeysWithValues: decoded.compactMap { (key,value) -> (Int, [ContentType: Int])? in
if let int = Int(key) {
return (int, value)
} else {
return nil
}
})
} catch {
print(error)
}
On this line:
(($0.value as? [String:String]).map {
You using not Sequence.map, but Optional.map.
Working solution:
/// First let's map plain types to our types
let resultArray = original_values
.compactMap { (key, value) -> (Int, [ContentType: Int])? in
guard let iKey = Int(key), let dValue = value as? [String: String] else { return nil }
let contentValue = dValue.compactMap { (key, value) -> (ContentType, Int)? in
guard let cKey = ContentType(rawValue: key), let iValue = Int(value) else { return nil }
return (cKey, iValue)
}
let contentDict = Dictionary(uniqueKeysWithValues: contentValue)
return (iKey, contentDict)
}
let result = Dictionary(uniqueKeysWithValues: resultArray)
To improve print output add conform to CustomStringConvertible:
extension ContentType: CustomStringConvertible {
var description: String {
switch self {
case .Tables:
return "Tables"
case .Chairs:
return "Chairs"
}
}
}
This is Swift 5 correct syntax
enum ContentType: String {
case tables = "Tables"
case chairs = "Chairs"
}
let originalValues: [String: [String: String]]
= ["1234": ["Tables": "5", "Chairs": "2"]]
let values: [Int: [ContentType: Int]] = Dictionary(uniqueKeysWithValues:
originalValues.map { arg in
let (key, innerDict) = arg
let outMap: [ContentType: Int] = Dictionary(uniqueKeysWithValues:
innerDict.map { innerArg in
let (innerKey, innerValue) = innerArg
return (ContentType.init(rawValue: innerKey)!, Int(innerValue)!)
}
)
return (Int(key)!, outMap)
}
)
print(values)
[1234: [__lldb_expr_5.ContentType.tables: 5, __lldb_expr_5.ContentType.chairs: 2]]
I'd like to loop trough every key of mystruct and print its key and its value for every property.
struct mystruct {
var a = "11215"
var b = "21212"
var c = "39932"
}
func loopthrough {
for (key, value) in mystruct {
print("key: \(key), value: \(value)") // Type mystruct.Type does not conform to protocol 'Sequence'
}
}
But using the few lines from above I always get this error message:
Type mystruct.Type does not conform to protocol 'Sequence'
How can I avoid getting this message?
First of all let's use CamelCase for the struct name
struct MyStruct {
var a = "11215"
var b = "21212"
var c = "39932"
}
Next we need to create a value of type MyStruct
let elm = MyStruct()
Now we can build a Mirror value based on the elm value.
let mirror = Mirror(reflecting: elm)
The Mirror value does allow us to access all the properties of elm, here's how
for child in mirror.children {
print("key: \(child.label), value: \(child.value)")
}
Result:
key: Optional("a"), value: 11215
key: Optional("b"), value: 21212
key: Optional("c"), value: 39932
use following code to get array of all the properties
protocol PropertyLoopable
{
func allProperties() throws -> [String]
}
extension PropertyLoopable {
func allProperties() throws -> [String] {
var result: [String] = []
let mirror = Mirror(reflecting: self)
// Optional check to make sure we're iterating over a struct or class
guard let style = mirror.displayStyle, style == .struct || style == .class else {
throw NSError()
}
for (property,_) in mirror.children {
guard let property = property else {
continue
}
result.append(property)
// result[property] = value
}
return result
}
}
Now just
let allKeys = try self.allProperties()
Don't forgot to implement protocol
Hope it is helpful
You can use runtime introspection (on an instance of your type) combined with value-binding pattern matching to extract the property names and values; the latter used to unwrap the optional label property of the Mirror instance used to represent the sub-structure of your specific instance.
E.g.:
struct MyStruct {
let a = "11215"
let b = "21212"
let c = "39932"
}
// Runtime introspection on an _instance_ of MyStruct
let m = MyStruct()
for case let (label?, value) in Mirror(reflecting: m)
.children.map({ ($0.label, $0.value) }) {
print("label: \(label), value: \(value)")
} /* label: a, value: 11215
label: b, value: 21212
label: c, value: 39932 */
I hope it still helps someone:
This is my version of the protocol for more complicated classes/structs (Objects within Objects within Objects ;-) )
I am sure there is a more elegant functional solution but this was a quick and dirty solution, as I only needed it for a temporary log.
protocol PropertyLoopable {
func allProperties() -> [String: Any]
}
extension PropertyLoopable {
func allProperties() -> [String: Any] {
var result: [String: Any] = [:]
let mirror = Mirror(reflecting: self)
// make sure we're iterating over a struct or class
guard let style = mirror.displayStyle, style == .struct || style == .class else {
print("ERROR: NOT A CLASS OR STRUCT")
return result
}
for (property, value) in mirror.children {
guard let property = property else {
continue
}
// It was a very complicated struct from a JSON with a 4 level deep structure. This is dirty dancing, remove unnecessary "for" loops for simpler structs/classes
// if value from property is not directly a String, we need to keep iterating one level deeper
if value is String {
result.updateValue(value, forKey: property)
} else {
let mirror = Mirror(reflecting: value)
for (property, value) in mirror.children {
guard let property = property else {
continue
}
//let's go for a second level
if value is String {
result.updateValue(value, forKey: property)
} else {
let mirror = Mirror(reflecting: value)
for (property, value) in mirror.children {
guard let property = property else {
continue
}
//3rd level
if value is String {
result.updateValue(value, forKey: property)
} else {
let mirror = Mirror(reflecting: value)
for (property, value) in mirror.children {
guard let property = property else {
continue
}
result.updateValue(value, forKey: property)
}
}
}
}
}
}
}
return result
}
}
I some optionals: numberOfApples:Int?, numberOfBananas:Int?, numberOfOlives:Int? and I'd like to create a dictionary of just the set values. Is there way do succinctly create this?
The closest I've got is:
// These variables are hard-coded for the example's
// sake. Assume they're not known until runtime.
let numberOfApples: Int? = 2
let numberOfBananas: Int? = nil
let numberOfOlives: Int? = 5
let dict: [String:Int?] = ["Apples" : numberOfApples,
"Bananas" : numberOfBananas,
"Olives" : numberOfOlives]
And I'd like to dict to be of type: [String:Int] like so:
["Apples" : 2,
"Olives" : 5]
But this gives me a dictionary of optionals and accessing a value by subscripting gives my a double-wrapped-optional.
I realise that I could do this with a for-loop, but I was wondering if there's something more elegant.
Many thanks in advance.
Personally I would do it this way (and it's how I personally do this when it comes up):
var dict: [String: Int] = [:]
dict["Apples"] = numberOfApples
dict["Bananas"] = numberOfBananas
dict["Olives"] = numberOfOlives
Simple. Clear. No tricks.
But if you wanted to, you could write Dictionary.flatMapValues (to continue the pattern of Dictionary.mapValues). It's not hard. (EDIT: Added flattenValues() to more closely match original question.)
extension Dictionary {
func flatMapValues<T>(_ transform: (Value) throws -> T?) rethrows -> [Key: T] {
var result: [Key: T] = [:]
for (key, value) in self {
if let transformed = try transform(value) {
result[key] = transformed
}
}
return result
}
func flattenValues<U>() -> [Key: U] where Value == U? {
return flatMapValues { $0 }
}
}
With that, you could do it this way, and that would be fine:
let dict = [
"Apples" : numberOfApples,
"Bananas": numberOfBananas,
"Olives" : numberOfOlives
].flattenValues()
You can use filter and mapValues. You first filter all pairs where the value is not nil and then you can safely force unwrap the value. This will change the dict type to [String: Int].
let dict = [
"Apples": numberOfApples,
"Bananas": numberOfBananas,
"Olives": numberOfOlives
]
.filter({ $0.value != nil })
.mapValues({ $0! })
print(dict) //["Olives": 5, "Apples": 2]
Try this:
let numberOfApples: Int? = 5
let numberOfBananas: Int? = nil
let numberOfOlives: Int? = 5
let dict: [String: Int?] = [
"Apples": numberOfApples,
"Bananas": numberOfBananas,
"Olives": numberOfOlives
]
extension Dictionary {
func flatMapValues<U>() -> [Key: U] where Value == Optional<U> {
return reduce(into: [:]) { $0[$1.key] = $1.value }
// Keeping this line as it provides context for comments to this answer. You should delete it if you copy paste this.
// return filter { $0.value != nil } as! [Key : U]
}
}
let unwrappedDict = dict.flatMapValues()
let foo: Int?? = dict["Apples"]
let bar: Int? = unwrappedDict["Apples"]
I'm looking for a type safe, generic version of this answer.
This is the method signature I'm looking for:
extension Dictionary where Value == Optional<T> {
func filterNil() -> <Key, T>
}
Is there any way to express this in Swift 3?
Edit:
My motivation for creating a Dictionary with optional values is that I need something like this:
struct User {
var mail: String?
var name: String?
func marshaled() -> [String: Any] {
return [
"mail": mail,
"name": name
].filterNil()
}
}
I much prefer the dictionary literal to creating an empty dictionary and filling the values manually.
Update: As of Swift 5 this would be:
let filtered = dict.compactMapValues { $0 }
Update: As of Swift 4, you can simply do
let filtered = dict.filter( { $0.value != nil }).mapValues( { $0! })
It is currently being discussed if Dictionary should get
a compactMapValues method which combines filter and mapValues.
(Previous answer:)
You can use the same "trick" as in How can I write a function that will unwrap a generic property in swift assuming it is an optional type? and Creating an extension to filter nils from an Array in Swift:
define a protocol to which all optionals conform:
protocol OptionalType {
associatedtype Wrapped
func intoOptional() -> Wrapped?
}
extension Optional : OptionalType {
func intoOptional() -> Wrapped? {
return self
}
}
Then your dictionary extension can be defined as:
extension Dictionary where Value: OptionalType {
func filterNil() -> [Key: Value.Wrapped] {
var result: [Key: Value.Wrapped] = [:]
for (key, value) in self {
if let unwrappedValue = value.intoOptional() {
result[key] = unwrappedValue
}
}
return result
}
}
Example:
let dict = ["mail": nil, "name": "John Doe"] // Type is [String : String?]
let filtered = dict.filterNil() // Type is [String : String]
print(filtered) // Output: ["name": "John Doe"]
I'd like to build a dictionary of dictionaries. In Swift how do I declare a dictionary with a key of a String and the value of a dictionary of this same type? I need to be able to have potentially infinite nests. (Kind of like building a tree using nodes. Except it's not a tree, it's a dictionary.)
I tried using AnyObject, but get a conversion error:
var node1: Dictionary<String, AnyObject?> = ["foo" : nil]
var node2: Dictionary<String, AnyObject?> = ["bar" : node1] // ERROR: Cannot convert value of type 'Dictionary<String, AnyObject?>' (aka 'Dictionary<String, Optional<AnyObject>>') to expected dictionary value type 'Optional<AnyObject>'
Is there a type-safe way of doing this (i.e., not using AnyObject?)
You can achieve something like this with a nice API and type safety in swift by using a struct and an enumeration.
enum RecursiveDictValue<KeyType: Hashable, ValueType> {
case Value(ValueType)
case Dict(RecursiveDict<KeyType, ValueType>)
}
struct RecursiveDict<KeyType: Hashable, ValueType> {
typealias OwnType = RecursiveDict<KeyType, ValueType>
private var dict: [KeyType: RecursiveDictValue<KeyType, ValueType>]
init() {
dict = [:]
}
init(dict: [KeyType: RecursiveDictValue<KeyType, ValueType>]) {
self.dict = dict
}
// this ensures that we can safely chain subscripts
subscript(key: KeyType) -> OwnType {
get {
switch dict[key] {
case let .Dict(dict)?:
return dict
default:
return RecursiveDict<KeyType, ValueType>()
}
}
set(newValue) {
dict[key] = .Dict(newValue)
}
}
subscript(key: KeyType) -> ValueType? {
get {
switch dict[key] {
case let .Value(value)?:
return value
default:
return nil
}
}
set(newValue) {
if let newValue = newValue {
dict[key] = RecursiveDictValue<KeyType, ValueType>.Value(newValue)
} else {
dict[key] = nil
}
}
}
}
This works quite nicely (note that you need to help swift with the types though):
var dict = RecursiveDict<String, Int>(dict: ["value":.Value(1),
"dict":.Dict(RecursiveDict<String, Int>(dict: ["nestedValue": .Value(2)]))])
if let value: Int = dict["value"] {
print(value) // prints 1
}
if let value: Int = dict["dict"]["nestedValue"] {
print(value) // prints 2
}
It also fails as intended when you do stuff that can't work.
if let value: Int = dict["dict"] {
print(value) // is not executed
}
if let value: Int = dict["dict"]["nestedDict"]["nestedValue"] {
print(value) // is not executed
}
And you can even set values in nested dictionaries that haven't been created yet!:
dict["dict"]["nestedDict2"]["nestedValue"] = 3
if let value: Int = dict["dict"]["nestedDict2"]["nestedValue"] {
print(value) // prints 3
}
I was working with firebase, and i needed to achieve an structure similar to this:
["llave3": ["hola": "", "dos": ""], "llave1": ["hola": "", "dos": ""], "llave2": ["hola": "", "dos": ""]]
This is a nested dictionary, or a dictionary of dictionaries. I achieve this by simply doing this:
var array = ["llave1", "llave2","llave3"]
var dictOfDictionarys = [String : [String : String]] ()
for items in array {
dictOfDictionarys[items] = ["hola":"","dos":""]
}
Very less info.. and you mean infinite nested dictionaries? I dont think so..
func returnDict() -> Dictionary<String, AnyObject> {
return ["Got You" : returnDict()]
}
var x : Dictionary<String, AnyObject> = ["GotYou" : returnDict()]
Just saying, nothing better can happen to this other than a crash
this is a case of infinite recursion. When you have infinite dictionaries, it doesnt mean that it is going to run forever. It means that it is going to run till your device runs out of memory. A call to function returnDict, calls returnDict, which again calls returnDict and so on.
A recursion is basically adding a method onto the stack of pre-existing stack of methods in memory.. this can happen until the stack overflows. Hence, stackOverFlow
let node1: Dictionary<String, AnyObject!> = ["foo" : nil]
var node2 = ["bar" : node1]
Playground approves of it
The reason is that like in Objective-C values in the Dictionary type must be non-optional.
It's not very useful anyway because in Swift assigning a nil value to a key removes the key.
var node1: Dictionary<String, AnyObject> = ["foo" : "Hello"]
var node2: Dictionary<String, AnyObject> = ["bar" : node1]