How do I update Swift Dictionary values of mixed types, in particular Arrays - swift

I have a dictionary of mixed types (string, NSImage, and an Array). When appending to the array, I get the error "Value of type 'Any??' has no member 'append'". I don't see how to cast "file_list" value as an Array so I can append values to it.
var dataDict: [String:Any?] = [
"data_id" : someString,
"thumbnail" : nil,
"file_list" : [],
]
// do stuff... find files... whirrr wizzzz
dataDict["thumbnail"] = NSImage(byReferencingFile: someFile)
dataDict["file_list"].append( someFile ) <- ERROR: Value of type 'Any??' has no member 'append'

You can't. You need to first get your key value, cast from Any to [String], append the new value and then assign the modified array value to your key:
if var array = dataDict["file_list"] as? [String] {
array.append(someFile)
dataDict["file_list"] = array
}
or
if let array = dataDict["file_list"] as? [String] {
dataDict["file_list"] = array + [someFile]
}
Another option is to create a custom struct as suggested in comments by OOPer

Related

appending key value pair to existing dictionary values in swift

I'm trying achieve below results. Where I can save multiple key values for multiple string items.
//dict["Setting1"] = ["key1":"val1"]
//dict["Setting1"] = ["key2":"val2"]
//dict["Setting2"] = ["key1":"val1"]
//dict["Setting2"] = ["key2":"val2"]
// and so on..
//or
//dict["Setting1"].append(["key2":"val2"]) // this doesn't work
//accessing dict["Settings1"]["key1"] ..should give me val1
var dict = [String:[String:String]]()
var lst1 = ["key2":"val2"]
dict["one"] = ["key1":"val1"]
dict["one"]?.append(lst1)
print(dict)
gives me error
error: value of type '[String : String]' has no member 'append'
obj["one"]?.append(lst1)
~~~~~~~~~~~ ^~~~~~
You're using a Dictionary which doesn't have methods like append(_:). append(:_) adds something to the end of an Array, but Dictionaries are unordered.
To add something to a Dictionary, you first define a key for it, and then assign it a value in the Dictionary
It'll look like this:
var dict = [String :[String: String]]()
var lst1 = ["key2": "val2"]
dict["one"] = ["key1": "val1"]
But you can't append to dict["one"], because it's not an array, you can only overwrite it
dict["one"] = lst1

Getting Array value in a dictionary swift

I am trying to get key and value in a Dictionary while I am able to the key and map it to a dictionary, I am unable to get the value which is an array.
var dict = [String: [String]]
I was able to get the key as an array which is what I want like:
var keyArray = self.dict.map { $0.key }
How can I get the value which is already an array
Use flatMap if you want to flatten the result you get when you use map which is of type [[String]].
let valueArray = dict.flatMap { $0.value } // gives `[String]` mapping all the values
Here is how you get each string count Array
var dict = [String: [String]]()
let countOfEachString = dict.map { $0.value }.map{ $0.count }
Each value is a string array .. so to access each array you need to use map again

Cannot subscript a value of type '[[String : Any]]' with an index of type 'String' error

I receive the following error:
Cannot subscript a value of type '[[String : Any]]' with an index of
type 'String'
on this line of code:
let temp = Int (weatherMain["temp"] as? Double ?? 0)
I'm a beginner in Xcode please help
You are casting the type as [String: Any]
Where you should cast as [[String: Any]]
Something like:
let temp = Int (weatherMain[0]["temp"] as? Double ?? 0)
You need to pass index.
weatherMain is an array of dictionaries. I dont know how you are storing the data, but to access the ["temp"] value, you need to do weatherMain[0]["temp"] where 0 is the index.
Cannot subscript a value of type '[[String : Any]]' with an index of
type 'String'
[[String : Any]] is an Array of Dictionaries and Array is accessible through Int indexes and not String.
So, you need to first fetch the Dictionary from Array using Int index and then access key-value pair from that Dictionary using String.
let temp = Int (weatherMain["temp"] as? Double ?? 0)
In the above code, assuming that weatherMain is of type [[String : Any]], to access key "temp" from a Dictionary, you need to first fetch that dictionary from the array, i.e.
let dict = weatherMain[0]
let temp = Int(dict["temp"] as? Double ?? 0)

What is the best way in Swift 4+ to store a set of homogenous arrays for various types in a dictionary?

Consider a situation where we want to have a dictionary of arrays, with each array being a homogeneous collection of values of some type (which may be a struct or a primitive type). I'm currently using the ObjectIdentifier of the type defining it thusly:
let pInts : [UInt32] = [4, 6, 99, 1001, 2032]
let pFloats : [Float] = [3.14159, 8.9]
let pBools : [Bool] = [true, false, true]
let myDataStructure : [ObjectIdentifier : [Any]] = [
ObjectIdentifier(Float.self) : pFloats,
ObjectIdentifier(UInt32.self) : pInts,
ObjectIdentifier(Bool.self) : pBools
]
The issue here is that when traversing the data structure, Swift doesn't know that the objects in each list are homogeneous. Since swift is statically typed, I'm guessing it is not possible to typecast the [Any] lists using the ObjectIdentifier keys. Consider this traversal pseudocode:
for (typeObjId, listOfValuesOfSometype) in myDataStructure {
// do something like swap values around in the array,
// knowing they are homogeneously but anonymously typed
}
So, is there some metatype machinery I can concoct to represent this data structure in a way that does not anticipate the list of actual types that will have arrays in it?
I'm not exactly sure what you want to accomplish, Inside the dictionary loop the arrays will always be of type Any, but if you want to move items in the arrays around, you could just do that. Just reassign the array first to a var and then put it back in the dictionary.
If you do want to loop through the items of a specific type, then you could use the array helper function below.
func testX() {
let pInts: [UInt32] = [4, 6, 99, 1001, 2032]
let pFloats: [Float] = [3.14159, 8.9]
let pBools: [Bool] = [true, false, true]
var myDataStructure: [ObjectIdentifier: [Any]] = [
ObjectIdentifier(Float.self): pFloats,
ObjectIdentifier(UInt32.self): pInts,
ObjectIdentifier(Bool.self): pBools
]
// Swap the first 2 items of every array
for d in myDataStructure {
var i = d.value
if i.count > 1 {
let s = i[0]
i[0] = i[1]
i[1] = s
}
myDataStructure[d.key] = i
}
// Now dump all data per specific type using the array helper function.
for i: UInt32 in array(myDataStructure) {
print(i)
}
for i: Float in array(myDataStructure) {
print(i)
}
for i: Bool in array(myDataStructure) {
print(i)
}
}
func array<T>(_ data: [ObjectIdentifier: [Any]]) -> [T] {
return data[ObjectIdentifier(T.self)] as? [T] ?? []
}

Swift dictionary, a key with multiple values

I would like to know how I can make a key of a dictionary have multiple values according to the data that comes to it.
Attached basic example:
var temp = [String: String] ()
temp ["dinningRoom"] = "Table"
temp ["dinningRoom"] = "Chair"
In this case, I always return "Chair", the last one I add, and I need to return all the items that I am adding on the same key.
In this case, the "dinningRoom" key should have two items that are "Table" and "Chair".
You can use Swift Tuples for such scenarios.
//Define you tuple with some name and attribute type
typealias MutipleValue = (firstObject: String, secondObject: String)
var dictionary = [String: MutipleValue]()
dictionary["diningRoom"] = MutipleValue(firstObject: "Chair", secondObject: "Table")
var value = dictionary["diningRoom"]
value?.firstObject
You can declare a dictionary whose value is an array and this can contain the data you want, for example:
var temp = [String: [String]]()
temp["dinningRoom"] = ["Table", "Chair", "Bottle"]
If you want to add a new element you can do it this way:
if temp["dinningRoom"] != nil {
temp["dinningRoom"]!.append("Flower")
} else {
temp["dinningRoom"] = ["Flower"]
}
Now temp["dinningRoom"] contains ["Table", "Chair", "Bottle", "Flower"]
Use Dictionary like this:
var temp = [String: Any]()
temp["dinningRoom"] = ["Table", "Chair"]
If you want to fetch all the elements from dinningRoom. You can use this:
let dinningRoomArray = temp["dinningRoom"] as? [String]
for room in dinningRoomArray{
print(room)
}
It is not compiled code but I mean to say that we can use Any as value instead of String or array of String. When you cast it from Any to [String]
using as? the app can handle the nil value.