Expected ':' in dictionary literal - swift

This is my first attempt to create a Dictionary:
var powerup: Dictionary = [String: Any]()
powerup = [
"dynamite" :
["tier0":
["effect" : 0]],
["tier1" :
["effect" : 1]]
]
I get the error 'Expected ':' in dictionary literal'. What is wrong with my dictionary?

It should be like that:
var powerup: Dictionary = [String: Any]()
powerup = [
"dynamite" :
[
"tier0":
["effect" : 0],
"tier1" :
["effect" : 1]
]
]
Count your brackets

It's fairly normal since you forget something in you dictionary literal.
I think this will work better :
powerup = ["dynamite":
[
["tier0":
["effect": 0]
],
["tier1" :
["effect": 1]
]
]
]
This is what you need to do if you want to describe a dictionary containing one key named dynamite linked to an array that contains two dictionary each one containing one key linked to a dictionary containing one key linked to one integer value.
You may want to rethink you data structure to since it's quite complicated.

Related

Remove Dictionary VALUE when value is of type Array

I have a dictionary which is of:
var myDictionary: [String: [String]]
It has within it a list of items, and the KEY is the start of the items letter (similar to a contact list) and the value is a String array.
myDictionary = [String: [String]] = [ "a": [
"Ace", "Aemc", "Allegro", "Ames", "Amprobe", "Anvil", "Appion", "Apple", "Arrow"
],
"b": [
"Bacharach", "Bauer", "Big Tex", "Black & Decker", "BMW", "Bobcat", "Bosch", "Bostitch", "Brady", "Briggs & Stratton", "Brother", "Burndy"
]
]
Similar to a search, I want to be able to find an item in the VALUES array but if it does exist, I want to REMOVE it from the dictionary. Meaning, in the above, I want to be able to return a new dictionary WITHOUT that item.
So as an examples, from the code above, if I were to type in ACE, I would like to return a new Dictionary [String: [String]] WITHOUT 'Ace' in it.
Now I am able to iterate on the items found via:
for items in myDictionary where items.value.contains("Ace")
But I cannot find a way to remove just this one Value entry.
All searches I have found only show either removing the entire dictionary entry (removing via the key) but not an actual item from the Value.
Any thoughts or suggestions are greatly appreciated. Thx
You have to remove the item in place
Get the first letter of the query lowercased.
Check if the array at given key exists and get the index of the query if available
Remove the item at index
var myDictionary : [String: [String]] = [ "a": [
"Ace", "Aemc", "Allegro", "Ames", "Amprobe", "Anvil", "Appion", "Apple", "Arrow"
],"b": [
"Bacharach", "Bauer", "Big Tex", "Black & Decker", "BMW", "Bobcat", "Bosch", "Bostitch", "Brady", "Briggs & Stratton", "Brother", "Burndy"
]]
let query = "Ace"
let indexLetter = String(query.prefix(1).lowercased())
if let value = myDictionary[indexLetter], let index = value.firstIndex(of: query) {
myDictionary[indexLetter]!.remove(at: index)
}

How to Append to complex dictionary types in swift 3

How to append some empty array values to the below dictionary.
var results:Dictionary<String, Array<Dictionary<String, Any>> = [:]
results["key"] = nil doesn't work for me.
I want to have a dictionary like
{
"key1" : [],
"key2" : [],
"key3" : []
}
And should be possible to add Dictionary<String, Any> later in the place of ()
First of all, your first line is illegal. It won't even compile. Please try always to show real code. So, your declaration might look like this:
var results : Dictionary<String, Array<Dictionary<String, Any>>> = [:]
Then to add an empty array to the dictionary, you would say:
results["key"] = []

Type Any has no subscript members while adding an array to [String: Any] in Swift3

In my Swift3 code I have an array:
var eventParams =
[ "fields" :
[ "photo_url":uploadedPhotoURL,
"video_url":uploadedVideoURL
]
]
Later on I want to add another array to this array, I thought I could just do:
eventParams["fields"]["user_location"] = [
"type":"Point", "coordinates":[appDelegate.longitude, appDelegate.latitude]
]
but I'm getting error here:
Type Any? has no subscript members
How can I add that array to my previously declared array fields?
Since your dictionary is declared as [String : Any], the compiler doesn't know that the value for "fields" is actually a dictionary itself. It just knows that it's Any. One very simple way to do what you're trying is like this:
(eventParams["fields"] as? [String : Any])?["user_location"] = [
"type":"Point", "coordinates":[appDelegate.longitude, appDelegate.latitude]
]
This will just do nothing if eventParams["fields"] is nil, or if it's not actually [String : Any].
You can also do this in a couple steps to allow for troubleshooting later on like this:
//Get a reference to the "fields" dictionary, or create a new one if there's nothig there
var fields = eventParams["fields"] as? [String : Any] ?? [String : Any]()
//Add the "user_location" value to the fields dictionary
fields["user_location"] = ["type":"Point", "coordinates":[appDelegate.longitude, appDelegate.latitude]]
//Reassign the new fields dictionary with user location added
eventParams["fields"] = fields

Dictionary reference not updating dictionary

I have a reference to a dictionary and when I debug the code I can see that the reference is being populated but the actual dictionary is not getting any of the values.
var newItems = [String:Dictionary<String,AnyObject>]()
for item in self.items{
let itemRef = ref.child("items").childByAutoId()
//let itemOptions: NSMutableArray = []
//let itemRemovedOptions: NSMutableArray = []
//let itemDiscounts: NSMutableArray = []
newItems.updateValue([String:AnyObject](), forKey: "\(itemRef.key)")
newItems["\(itemRef.key)"]?.updateValue(item.parentCategory.id, forKey: "parentCategoryId")
newItems["\(itemRef.key)"]?.updateValue(item.item.id, forKey: "itemId")
newItems["\(itemRef.key)"]?.updateValue(item.item.name, forKey: "name")
newItems["\(itemRef.key)"]?.updateValue(item.qty, forKey: "qty")
newItems["\(itemRef.key)"]?.updateValue(item.discountAmount, forKey: "discountAmount")
newItems["\(itemRef.key)"]?.updateValue(item.notes, forKey: "notes")
newItems["\(itemRef.key)"]?.updateValue(item.price, forKey: "price")
//set options
newItems["\(itemRef.key)"]?.updateValue([String:Dictionary<String,AnyObject>](), forKey: "options")
for option in item.options{
if var optionsRef = newItems["\(itemRef.key)"]?["options"] as? [String:Dictionary<String,AnyObject>]{
optionsRef.updateValue([String:AnyObject](), forKey: "\(option.item.id)")
optionsRef["\(option.item.id)"]?.updateValue(option.item.name, forKey: "name")
optionsRef["\(option.item.id)"]?.updateValue(option.group.id, forKey: "group")
optionsRef["\(option.item.id)"]?.updateValue(option.qty, forKey: "qty")
optionsRef["\(option.item.id)"]?.updateValue(option.price, forKey: "price")
}
}
}
The primary issue here is that when you say if var optionsRef = newItems["\(itemRef.key)"]?["options"] as? [String:Dictionary<String,AnyObject>], you're making a copy of the Dictionary, since Dictionaries are value types in Swift. As a result, all subsequent modifications of the dictionary are applied only to your local copy, and not the one you intended. To alleviate this, you must assign the modified version of the dictionary back into the data structure where you wanted it changed.
But in addition to that primary problem, there are many other, softer, issues with this code. There's a reason this question over 50 views and no answers. People see this, say "Nope!" and run away screaming. Here are some key points:
Be consistent with your use of shorthand notation. [String : [String : AnyObject], not [String : Dictionary<String, AnyObject>].
Don't use string interpolation ("\(foo)") solely to convert types to strings. If the values are already strings, use them directly. If they're not, convert them with String(foo).
Don't use updateValue(_:forKey:). There's pretty much never a reason. Prefer subscript syntax.
When initializing a complex structure (such as your dictionary), initialize it first, then add it. Don't add it, then repeatedly access it through cumbersome copy/pasting.
In your case, consider newItems["\(itemRef.key)"]?.updateValue(.... With every line, the key must be hashed, and used to retrieve the value from the newItems dictionary. Then, the returned value must be checked for nil (by the ?. operator), doing nothing if nil, otherwise executing a method. You know the value won't be nil because you set it, but it has to do all this checking anyway.
Prefer Dictionary literals over mutation wherever possible.
Don't use Foundation data structures (NSArray, NSDictionary, etc.) it's absolutely necessary.
Here's my take on this code. It might need some touch ups, but the idea is there:
var newItems = [String : [String : AnyObject]() //fixed inconsistent application of shorthand syntax
let itemRef = ref.child("items").childByAutoId() //this shouldn't be in the loop if it doesn't change between iterations
for item in self.items {
// There's pretty much no reason to ever use updateValue(_:forKey:), when you can just use
// subscript syntax. In this case, a Dictionary literal is more appropriate.
var optionsDict = [String : [String : AnyObject]();
for option in item.options {
optionsDict[option.item.id] = [
"name" : option.item.name,
"group" : option.group.id,
"qty" : option.qty,
"price" : option.price,
]
}
newItems[itemRef.key] = [
"parentCategoryId" : item.parentCategory.id,
"itemId" : item.item.id,
"name" : item.item.name,
"qty" : item.qty,
"discountAmount" : item.discountAmount,
"notes" : item.notes,
"price" : item.price,
"options" : optionsDict
]
}
Here's an alternative that avoids having to define optionsDict separately:
let itemRef = ref.child("items").childByAutoId()
for item in self.items {
newItems[itemRef.key] = [
"parentCategoryId" : item.parentCategory.id,
"itemId" : item.item.id,
"name" : item.item.name,
"qty" : item.qty,
"discountAmount" : item.discountAmount,
"notes" : item.notes,
"price" : item.price,
"options" : item.options.reduce([String : AnyObject]()) { (var dict, option) in
optionsDict[option.item.id] = [
"name" : option.item.name,
"group" : option.group.id,
"qty" : option.qty,
"price" : option.price,
]
}
]
}

How to 'switch' based on keys contained in a dictionary in Swift?

I want to execute different branches based on what keys a dictionary contains, here's some code you can paste into a playground that shows what I currently do:
let dict1 = ["a" : 1, "thingy" : 2]
let dict2 = ["b" : 3, "wotsit" : 4]
let dict = dict1 // Change this line to see different outcomes
if let valueA = dict["a"],
let thingy = dict["thingy"] {
// Code for type with "a" and "thingy" keys
println("a/thingy")
} else if let valueB = dict["b"],
let wotsit = dict["wotsit"] {
// Code for type with "b" and "wotsit" keys
println("b/wotsit")
}
However, I think this would be more elegantly expressed as a switch statement - something like this:
let dict1 = ["a" : 1, "thingy" : 2]
let dict2 = ["b" : 3, "wotsit" : 4]
let dict = dict1 // Change this line to see different outcomes
switch dict {
case let a = dict["a"],
let thingy = dict["thingy"]:
// Code for type with "a" and "thingy" keys
println("a/thingy")
case let b = dict["b"],
let wotsit = dict["wotsit"]:
// Code for type with "b" and "wotsit" keys
println("b/wotsit")
default:
break
}
I have tried the above and various other attempts to express this logic in a switch but couldn't make it work. So how could I do this in a switch (or is this misguided in some way)?
Background:
The dictionaries are actually SwiftyJSON JSON objects loaded from JSON data, and I want to infer the 'type' of object these JSON structures represent, from what keys they contain - if they don't contain all the right keys for a particular object they won't attempt to load as that type. I could add a "type" to each JSON structure and switch based on that value, but I'd prefer to automatically infer their type from the keys as I currently do.