Getting a single Dictionary element into a variable - ios

I have a variable:
reas : [String:[User]]?
I want to sort it and put it in another view controller variable
vc.OrederReas = reas.sorted { $0.1.count > $1.1.count }
I'm getting an error that orderReas needs to be of type
[Dictionary<String, [User]>.Element]()
Which I made, Now I want to put a signal element from orderReas (which should be String:[User], and maybe sometimes all the elements, but this is not the issue).
but I don't know how to define it, I'm getting errors such as:
Cannot assign value of type 'Dictionary<String, [User]>.Element' (aka '(key: String, value: Array<User>)') to type '[Dictionary<String, [User]>.Element]' (aka 'Array<(key: String, value: Array<User>)>')
But I can't define a variable as
var OrederReas = Dictionary<String, [User]>.Element
To sum up I want a variable which holds [String:[User]], sort him into another variable, and Another variable which will hold one either one element or all the elements from the original variable.
Thank you!

When you are sorting a Dictionary the result will be a array Tuple of Key and Value.
in your case, if you want to have dictionaries of the same type you can convert your Result(Tuple) to a Dictionary so you can do this:
let tupleOrederReas = reas.sorted { $0.value.count > $1.value.count }
let dictionaryOrederReas = tupleOrederReas.reduce(into: [:]) { $0[$1.key] = $1.value }
//Finally Pass the Dictionary to VC variable
vc.OrederReas = dictionaryOrederReas

Related

fill dictionary values in loop

I have a dictionary var items = [String:String]()
Then I assign values :
for i in itemInCart {
items["param_id"] = i.modelId
//items["param_id"]?.append(i.modelId!)
}
print(items)
I have just a last value.
I know that the method append() is not applicable to dictionaries, but how can I fill it then?
This is because you are replacing param_id every time for loop i so it will always a last element you will found
You have two options, either create a unique key for each element (a bad idea) or if you want all the elements you have to create array and add it into the param_id key like:
items["param_id"] = itemInCart.map { $0.modelId }
so now your dictionary is [String:Any]() or [String:[String]]()

"Cannot subscript a value of type '[String]' with an index of type 'String'

I'm trying to display a dynamically updated array in a label using:
for i in result {
outputLbl.text = result[i].joinWithSeparator("\n")
}
However I get the error
Cannot subscript a value of type '[String]' with an index of type 'String'.
Any idea how I can fix this?
Note that when using the loop "header" for X in Y, you don't get the indices of Y, but the actual elements of Y. Judging from your error, results is an array of strings ([String]). Hence, i in you for loop represents---one by one---the elements in the String array results.
So, if you wanted to access the string elements one by one in the for loop above, you could use the approach in your example:
let result = ["Hello", "World"]
for myString in result {
// use each string element in some manner...
}
However, as you are using the array method joinWithSeparator(..), you should use, just as Leo writes in his comment above, this method directly on your array (and not their elements!)
let result = ["Hello", "World"]
outputLbl.text = result.joinWithSeparator("\n")
/* Hello\nWorld */
I think what you are doing here is trying to iterate through an array of string and then update a label that is in this case "outputLbl".Here you can do something like this
for i in result {
//result is array of strings.
// here i is individual element of result array
/* outputLbl.text = result[i].joinWithSeparator(“\n”)*/
//instead you can write
outputLbl.text = i.joinWithSeparator(“\n”)
}
The reason you are getting this error is as follows:
It seems you are confusing the type of i. The variable result is of type [String] which means it is an array of String types. By virtue of being an array, it must be subscripted with an Int, not a String. So something like result[0] or result[12] is valid, but something like result["hello"] is not valid. The variable i here is a String because it is a single element in an array of String types, which means that effectively, what you're trying to do by saying result[i] is something along the lines of result["hello"].
That having been said, the true solution to your problem is that the method joinWithSeparator(_:String) is not a String method but rather a Sequence type method. Which means it should be called on a Sequence like an object of type [String]. So what you should use is:
outputLbl.text = result.joinWithSeparator("\n")
What's going on here is the compiler is inferring i to be of type String since that's what result is. You should be more verbose in your naming conventions.
for specificString in result {
outputLbl1.text += "\n\(specifcString)"
}
EDITED for correctness.

I am creating objects with var because I mutate them but I get warning: "Variable 'variableName' was never mutated, consider..."

I am creating at launch Dictionaries with var because I will modify them later when user does something. Dictionaries are added inside an Array in a singleton class to be used in multiple places but I get the warning "Variable 'variableName' was never mutated, consider...."
in the place I am creating them
If I make them with let and when I get object form array to modify it if I take it from array with var, no crash, no warning, no nothing...
What is the explanation for this?
UPDATE:
My Singleton Class:
class Config {
static let sharedInstance = Config()
var array_shapes: Array<Dictionary<NSObject,AnyObject>> = Array()
func createInitialShapeArray(){
var avion = createShapeDictionaryFor("Avion", objectName: "Avion", badgeStatus: "0", shapeImageName: "shape_avion");
//.......more objects like avion
array_shapes = [avion,//.....the other objects];
}
func createShapeDictionaryFor(objectID:String, objectName:String, badgeStatus:String, shapeImageName:String) -> Dictionary<NSObject,AnyObject>{
var dict: Dictionary<NSObject,AnyObject> = [:]
dict["objectID"] = objectID
dict["objectName"] = objectName
dict["badgeStatus"] = badgeStatus
dict["shapeImageName"] = shapeImageName
return dict;
}
}
And when I am mutating dictionaries (In main class):
#IBAction func btnPressed_done(sender:UIButton){
pennyPincherGestureRecognizer.recognize();
screenShotMethod()
var dict = Config.sharedInstance.array_shapes[Config.sharedInstance.currentShapeIndex] as Dictionary<NSObject,AnyObject>
dict["badgeStatus"] = "1"
self.initNextShape()
}
var avion has the warning "Variable 'variableName' was never mutated, consider...."
It is not an error trough, it's a warning and I was curious if I could silence them or what can I do to make them dissappear
Facts
You are declaring avion as a local variable of the method createInitialShapeArray
You are not mutating avion in the scope where it is defined
avion is a Dictionary therefore a Struct (value type rules are applied)
Conclusion
There is no need to declare avion as a variable, it should be a constant.
Please note that where you write
array_shapes = [avion, ...]
you are creating a copy of avion (because it's a Dictionary).
So if you change the value inside array_shapes you are changing another value.
Therefore, at the end of the day, you are not mutating avion... and the compiler is right, it should be a constant.
Example
Please consider the following code
func foo() {
var dict = [1: "One"] // <-- Compiler warning
var anotherDict = dict
anotherDict[2] = "Two"
}
Here I am getting the same compiler warning
Variable 'dict' was never mutated; consider changing to 'let' constant
This happens because I am changing anotherDict that is not just another reference to the same value, it is actually a totally different value. This is the rule with Struct(s) and Enum(s) because they are Value Types.
Hope this helps.
In Swift arrays and dictionaries are declared as struct so when you pass them to other function or use them in assignments their value is copied and not passed as reference the same way it's done for classes, this means that when you pass avion to the append() function of your array you pass a copy of the dictionary so the original variable is never mutated.
The same things happens when you try to modify on dictionary in the array thus copying the dictionary of your interest in dict: you aren't modifying the array inside your shared instance but the local variable dict.

How to create and access a NSDictionary in Swift

I am busy converting to Swift and am trying to figure out how to do the following in Swift
NSArray arrayOfStrings1 = {#"Substring1", #"Substring2", nil};
Dictionary dict = {#"MainString1", arrayOfStrings1};
So in Swift I have the following:
var dictionary = [String: Array<String>]() // is this correct ??
var array: [String] = ["Substring1", "Substring2"]
dictionary["MainString1"] = ["Substring1.1", "Substring1.2"]
dictionary["MainString2"] = ["Substring2.1", "Substring2.2"]
Now in order to access the array I use
let array = dictionary["MainString1"]
let item0 = array[0]
but this fails with a compiler error which seems to indicate that array is in fact a String not an array of strings.
What am I missing here?
The issue is actually that a subscript lookup for a Dictionary in Swift returns an optional value:
This is a pretty great feature - you can't be guaranteed that the key you're looking for necessarily corresponds to a value. So Swift makes sure you know that you might not get a value from your lookup.
This differs a little bit from subscript behavior for an Array, which will always return a value. This is a semantically-driven decision - it's common in languages for dictionary lookups to return null if there is no key - but if you try to access an array index that does not exist (because it's out of bounds), an exception will be thrown. This is how Swift guarantees you'll get a value back from an array subscript: Either you'll get one, or you'll have to catch an exception. Dictionaries are a little more lenient - they're "used to" not having the value you're asking for.
As a result, you can use optional binding to only use the item if it actually has a value, like so:
if let theArray = dictionary["MainString1"] {
let item0 = theArray[0]
} else {
NSLog("There was no value for key 'MainString1'")
}

Trouble Unpacking Dictionary of Dictionaries in Swift

I am having a devil of a time trying to work with Dictionaries in Swift. I have created the following Dictionary of Dictionaries but I am unable to unpack it.
var holeDictionary = Dictionary<String,Dictionary<String,Dictionary<String,Int>>>()
I can get the first Dictionary out with:
var aDictionary = holeDictionary["1"]
But trying to access the next Dictionary within it gives me an error as follows:
var bDictionary = aDictionary["key"] // [String : Dictionary<String, Int>]?' does not have a member named 'subscript'
I know what the contents of the Dictionaries are and can verify them with a println(aDictionary). So how can I get to the Dictionaries buried deeper down?
The key subscript on Dictionary returns an optional, because the key-value pair may or may not exist in the dictionary.
You need to use an if-let binding or force unwrap the optional before you can access it to subscript it further:
if let aDictionary = holeDictionary["1"] {
let bDictionary = aDictionary["key"]
}
Edit, to add forced unwrap example:
If you're sure that the key "1" exists, and you're okay with assert()ing at runtime if the key doesn't exist, you can force-unwrap the optional like this:
let bDictionary = holeDictionary["1"]!["key"]
And if you're sure that the key "key" will exist, you'd do this instead:
let bDictionary = holeDictionary["1"]!["key"]!
Accordingly to the swift documentation:
Because it is possible to request a key for which no value exists,
a dictionary’s subscript returns an optional value of the dictionary’s
value type
When you retrieve an item from a dictionary you have an optional value returned. The correct way to handle your case is:
var holeDictionary = Dictionary<String,Dictionary<String,Dictionary<String,Int>>>()
if let aDictionary = holeDictionary["1"] {
var bDictionary = aDictionary["key"]
}

Resources