Swift access fields in nested dictionary - ios

I've got to deal with a Dictionary like this, or more nested.
How can I access fields like "twotwo" ? Or is there any better possibility to model such structure?
let nestedDict = [
"fieldOne": "name",
"fieldTwo": "name",
"fieldThree":
[
[
"twoOne": "some text",
"twoTwo": true,
"twoThree": 1e-40
],
[
"twoOne": "some text",
"twoTwo": true,
"twoThree": 1e-40
]
]
]

nestedDict is a Dictionary, you get fieldThree with
let fieldThree = nestedDict["fieldThree"] as! [[String:Any]] // [[String:AnyObject]] in Swift 2 and lower.
fieldThree is an Arrayof [String:AnyObject] dictionaries, you get the value of twoTwo of the first array item with
let twoTwo = fieldThree[0]["twoTwo"] as! Bool
You can even retrieve all values of key twoTwo in the array
let allTwoTwo = fieldThree.map { $0["twoTwo"] as! Bool }

Related

Filter an array in iOS shortcuts - how?

I have an array like this:
"vehicleStatus": [
{
"key": "TU_STATUS_PRIMARY_VOLT",
"value": "3.6"
},
{
"key": "TU_STATUS_PRIMARY_CHARGE_PERCENT",
"value": "100"
},
{
"key": "TU_STATUS_GSM_MODEM",
"value": "FUNCTIONING"
},
{
"key": "DOOR_IS_ALL_DOORS_LOCKED",
"value": "TRUE"
}
]
I want to retrieve the value of DOOR_IS_ALL_DOORS_LOCKED by filtering the array and without the "Repeat with each item" action.
I already filter arrays in other tools, JavaScript, Power Automate etc.
Is this possible in iOS Shortcuts?
I tried looping through all 97 items in this array and using IF condition to set a variable if the condition is met and then using that variable later, but it's long winded and takes too long for what I need.
1). For loop
First Solution of your problem, is already you have done.
Maybe you have done this by using for loop manually.
so second Option is
2). System Iterative
if let arrEle = vehicleStatus.first { $0.key == "DOOR_IS_ALL_DOORS_LOCKED"} {
print(arrEle.value)
}
or
if let arrEle = vehicleStatus.first { ($0 as? NsDict)?["key"] == "DOOR_IS_ALL_DOORS_LOCKED"} {
print((arrEle as? NsDict)?["value"] as? String)
}
or
if let arrEle = vehicleStatus.first { ($0 as? NsDict)?["key"] == "DOOR_IS_ALL_DOORS_LOCKED"},
let val = (arrEle as? NsDict)?["value"] as? String {
print(val)
}
you can change data management by
3). Dictionary
If 'vehicleStatus' has all data like you provide, then all data must be manage by dictionary.
let vehicleStatus = [
[
"key" : "TU_STATUS_PRIMARY_VOLT",
"value": "3.6"
],
[
"key" : "TU_STATUS_PRIMARY_CHARGE_PERCENT",
"value": "100"
],
[
"key" : "TU_STATUS_GSM_MODEM",
"value" : "FUNCTIONING"
],
[
"key" : "DOOR_IS_ALL_DOORS_LOCKED",
"value": "TRUE"
]
]
print(vehicleStatus)
let dict = Dictionary(uniqueKeysWithValues: vehicleStatus.map{ ($0["key"]!, $0["value"]! ) })
print(dict)

Save Nested Dictionary in UserDefaults and manage the duplication check [Swift 4.2]

I have a nested Dictionary required to save in UserDefaults and share to extension. The dictionary structure like below:
let dict = [
"Sections" : [
["Title" : "Title1", "Items": ["item1-1", "item1-2", "item1-3"]],
["Title" : "Title2", "Items": ["item2-1", "item2-2", "item2-3", "item2-4"]],
["Title" : "Title3", "Items": ["item3-1"]],
]
]
Which saved successfully with:
UserDefaults(suiteName: "group.identifier.test")!.setValue(dict, forKey: "savedDict")
But now I wish to get it back and check is Title2 already exists, if yes then delete it and add again with new Items
I used to do following but can't get the Title back:
let savedDict:[String:AnyObject] = UserDefaults(suiteName: "group.identifier.test")!.object(forKey: "savedDict") as! Dictionary
success to get the data under "Sections" by following code
let savedSection = savedDict["Sections"]
print("Saved Section: \(savedSection)")
but not able to get the Title with:
print("Saved Title: \(savedSection!["Title"])") *// return nil*
I tried for (key, value) too, but fired a data type error
for (key, value) in savedSection{ *// Type 'AnyObject?' does not conform to protocol 'Sequence'*
print("Key: \(key) Value: \(value)")
}
May I know is there any way to get the "Title" back for checking and update? Am I using the wrong way to store this kind of nested data?
Many Thanks!
in your code
print("Saved Title: \(savedSection!["Title"])") *// return nil*
here it should be
if let savedSection = savedDict["Sections"] as? [[String : Any]] { //EDIT***
print("Saved Title: \(savedSection[0]["Title"])") *// inplace of 0 any index you want,
}
as if now in your dictionary there are three elements in section so it safe to get value at 0, hope you understood that the underlying dictionary is array of dictionary in sections key, also instead of using dictionary you can use struct or class to save your data and while getting it retrieve it as that struct type.
First of all, never use KVC method setValue(:forKey with UserDefaults.
There is generic set(:forKey. And there is dictionary(forKey: to get a [String:Any] dictionary back
The value for key Sections is an array (index-based). Lets assume you have this new data
let newTitle2 : [String:Any] = ["Title" : "Title2", "Items": ["item4-1", "item4-2", "item4-3"]]
This is a way to load the dictionary – you should always safely check if the dictionary exists – update it and save it back. If the item for "Title2" exists it will be overwritten otherwise the new item is appended to the array.
let groupDefaults = UserDefaults(suiteName: "group.identifier.test")!
if var savedDict = groupDefaults.dictionary(forKey: "savedDict"),
var sections = savedDict["Sections"] as? [[String:Any]] {
if let title2Index = sections.firstIndex(where: {($0["Title"] as! String) == "Title2"}) {
sections[title2Index] = newTitle2
} else {
sections.append(newTitle2)
}
savedDict["Sections"] = sections
groupDefaults.set(savedDict, forKey: "savedDict")
}

how to add an object into a NSDictionary with respect to a key

I have NSDictionary, now I am trying to add an object in a particular key.How can I do that ? below is my code.
let businessPhoneDic = ["locationname" : "",
"area" : "",
"number" : "",
"type" : "",
];
let emailDic:NSMutableDictionary? = ["email" : "",];
let businessPhoneDic2 = ["locationname" : "hello",
"area" : "",
"phonenumber" : "",
"type" : "",
];
var mainDictionary = ["businessPhone" : businessPhoneDic as AnyObject,"email" : emailDic as AnyObject,
];
Now I want to add "businessPhoneDic2" into mainDictionary for key "businessPhone".How can I do that into Swift 3
By definition, you can't have two values mapped to the same key. The following code will replace the old key:
Swift 3
mainDictionary["businessPhone"] = businessPhoneDic2
Just use a new key if you need both values in your dictionary, or maybe store an array of dictionaries as values as such:
var mainDictionary : [String : [NSDictionary]] = ["businessPhone" : [businessPhoneDic]]
Then:
mainDictionary["businessPhone"]?.append(businessPhoneDic2)
First of all do not use MSMutable... collection types in Swift.
Use native Swift Dictionary
let emailDic = ["email" : ""]
Second of all annotate a dictionary with different types as [String:Any]
var mainDictionary : [String:Any] = ["businessPhone" : businessPhoneDic, "email" : emailDic]
If the value for key businessPhone is an array you can append the value. If it's a single dictionary you have to create an array.
This code considers both cases:
let businessPhone = mainDictionary["businessPhone"]
if var phone = businessPhone as? [[String:Any]] {
phone.append(businessPhoneDic2)
mainDictionary["businessPhone"] = phone
} else if let phone = businessPhone as? [String:Any] {
mainDictionary["businessPhone"] = [phone, businessPhoneDic2]
}
Try this :
mainDictionary["your key"] = businessPhoneDic2 as AnyObject // cast as per suggestions
Swift 3.x
// Initialize the Dictionary
var dict = ["name": "Foo", "surname": "Bar"]
// Add a new key with a value
dict["email"] = "foo.bar#email.com"
print(dict)

How do I sort an array of dictionary according to an array contents in Swift

I have an array of dictionary. I need to sort that array. The sorting shouldnt be like ascending or descending but it should be based on an another array contents.
EX: Lets say I have an array nammed array_unsorted and that array contains a lot of dictionary objects like d1, d2, d3, d4 etc. Each of the dictionary object has a key called key1 and each dictionary object has different value for that key such as Kammy, Maddy, Jessy. Lets say I have anohter sorted array which Maddy, Kammy, Jessy. Now the dictionary should be sorted in a way that the first element should the dictionary object in which the value for key1 should beMaddy`.
I cannot use SortDescriptor, because this will sort as an ascending or descending order based on the key passed to it.
I have tried my solution but I am ended up using so many nested loops. I feel like the solution I made so so pathetic that I dont even want to post the code here.
Any help would be so much appreciated.
EDIT: There can be multiple sorting arrays but as of now I am considering only one sorting array and then I can write the code for multiple sorting arrays.
How about this:
Create a new, empty dictionary with a String key, and a value of type Dictionary. Call it sourceItemsDict.
Loop through the dictionaries in your source array, and add each entry to your new dictionary, using your sort key as the dictionary key, and put the array entry as the value.
Create a new, empty array of dictionaries for your sorted results. call it sortedArray.
Now loop through your array that has the desired order in it. Fetch the item with that key from sourceItemsDict and append it to the end of sortedArray.
That should do it, and it should perform in O(n) time.
Try this:
func sort<T: Equatable>(arrayOfDict arr: [[String: T]], by key: String, order: [T]) -> [[String: T]] {
return arr.sorted {
guard let value0 = $0[key], let value1 = $1[key] else {
return false
}
guard let index0 = order.index(of: value0), let index1 = order.index(of: value1) else {
return false
}
return index0 < index1
}
}
let array_unsorted = [
["name": "Kammy", "city": "New York"],
["name": "Maddy", "city": "Cupertino"],
["name": "Jessy", "city": "Mountain View"]
]
let sortedByName = sort(arrayOfDict: array_unsorted, by: "name", order: ["Maddy", "Kammy", "Jessy"])
let sortedByCity = sort(arrayOfDict: array_unsorted, by: "city", order: ["Cupertino", "Mountain View", "New York"])
print(sortedByName)
print(sortedByCity)
Your question leaves a couple of unresolved scenarios:
1: What if the key is missing from a dictionary?
let array_unsorted = [
["name": "Kammy", "city": "New York"],
["city": "Las Vegas"],
["name": "Maddy", "city": "Cupertino"],
["name": "Jessy", "city": "Mountain View"]
]
let sortedByName = sort(arrayOfDict: array_unsorted, by: "name", order: ["Maddy", "Kammy", "Jessy"])
Should Las Vegas appear at the beginning or end of the sorted array?
2: What if you don't specify an order for a value?
let array_unsorted = [
["name": "Amy"],
["name": "Kammy", "city": "New York"],
["name": "Maddy", "city": "Cupertino"],
["name": "Jessy", "city": "Mountain View"]
]
let sortedByName = sort(arrayOfDict: array_unsorted, by: "name", order: ["Maddy", "Kammy", "Jessy"])
Now where should Amy be placed?
Check out this example:
let dic1 = ["name" : "a"]
let dic2 = ["name" : "b"]
let dic3 = ["name" : "c"]
let dic4 = ["name" : "d"]
let dic5 = ["name" : "e"]
let unsorted_array = [dic2,dic5,dic1,dic4,dic3]
func sortArrayByName(_ array:[[String:String]])->[[String:String]]{
var sortedArray:[[String:String]] = [[String:String]]()
var sortingOrder:[String] = [String]()
for eachDic in array{
if let name = eachDic["name"]{
sortingOrder.append(name)
sortingOrder.sort() // sorting logic here
if sortedArray.isEmpty{
sortedArray.append(eachDic)
} else {
let index = sortingOrder.index(of: name)!
sortedArray.insert(eachDic, at: index)
}
}
}
return sortedArray
}
let sorted_array = sortArrayByName(unsorted_array)

Create a particular JSON Structure in Swift

I'm having trouble creating a specific structure in JSON with Swift. I use Swifty JSON for parsing but I can't figure out how to create one.
I have this array which is filled by Id's and quantity Ints of products in a shopping basket . I need to get the array into my JSON but I don't know how.
If you could help me with this I would be very glad :)
var productArray = Array<(id: Int,quantity: Int)>()
let jsonObject: [String: AnyObject] = [
"order": 1,
"client" : 1,
"plats": [
for product in productArray
{
"id": product.id
"quantity": product.quantity
}
]
]
You can't just start looping through stuff while defining your dictionary. Here's another approach.
First, create your array:
var productArray = Array<(id: Int,quantity: Int)>()
Add some products (for testing):
productArray += [(123, 1000)]
productArray += [(456, 50)]
Map this array into a new array of dictionaries:
let productDictArray = productArray.map { (product) -> [String : Int] in
[
"id": product.id,
"quantity": product.quantity
]
}
Use the new mapped array in your JSON object:
let jsonObject: [String: AnyObject] = [
"order": 1,
"client" : 1,
"plats": productDictArray
]
You are not supposed to do any kind of looping/condition making block of codes while creating Array's or Dictionary. For that you need to execute that piece of code outside, create a variable and use it.
Do try this way.
var productArray = Array<(id: Int,quantity: Int)>()
var prods = [[String:Int]]()
for product in productArray
{
var eachDict = [String:Int]()
eachDict["id"] = product.id
eachDict["quantity"] = product.quantity
prods.append(eachDict)
}
let jsonObject: [String: AnyObject] = [
"order": 1,
"client" : 1,
"plats": prods
]

Resources