Get value from multidimensional array in swift - swift

I have the following array in Swift:
var words = [
"English" : ["Hello", "Bye"],
"Spanish" : ["Hola", "Adios"]
]
How can I get the value for index, something as the following doesn't work
print(words["English"][0])
It throws the error: Value of optional type Array? not unwrapped, did you mean to use ! or ? but that just makes it:
print(words["English"]?[0])
and still doesn't work, please help.

You need to look into how to unwrap optionals. For example, what you are trying to do could be done either of these two ways:
Force unwrapping:
print(words["English"]![0])
Safe unwrapping:
if let hello = words["English"]?[0]{
print(hello)
}

Related

Unexpectedly found nil while unwrapping an Optional value but value exist

I know I need to bind my varaible for unwrap but the problem is my value is not reconized but present.
This is my code :
surveyW.karmaWin = Int(endedSurvey["karma"].string!)
endedSurvey is a array dictionary of my JSON backend. I get a Unexpectedly found nil while unwrapping an Optional value error.
I specify that I force the unwrapping to show you my problem.
The problem is my array contains the karma value. I show you the screen of the value:
So we can see that the value existing. Why I get a Unexpectedly found nil...?
The value contained in "karma" is not String. You're trying to force cast it with SwiftyJSON but it tells you it has a nil. You first need to extract value as it is - .int, and after that convert that to something else if needed.
surveyW.karmaWin = endedSurvey["karma"].int
You can use intValue because SwiftyJSON has two kinds of "getters" for retrieving values: Optional and non-Optional
.string and .int are the optional getters for the String and Int representation of a value, so you have to unwrap it before use
if let fbId = fbJson["id"].string {
print(fbId)
}
If you are 100% sure that there will always be a value, you can use the equivalent of "force unwrap" by using the non-Optional getter and you don't need if let anymore:
let fbId = fbJson["id"].stringValue
In your code :
surveyW.karmaWin = endedSurvey["karma"].intValue
endedSurvey["karma"] is an Integer not string and also good way to unwrap an optional is:
if let karma = endedSurvey["karma"] as? Int{
surveyW.karmaWin = karma
}

Array of String printing Optional, why?

I am playing with Arrays in playground and I am bit confused. Here is code:
var players = ["tob", "cindy", "mindy"] //["tob", "cindy", "mindy"]
print(players.isEmpty) // False
var currentPlayer = players.first // "tob"
print(currentPlayer) // "Optional("tob")\n"
Why does it says "Optional"?
I found explanation: "The property first actually returns an optional, because if the array were empty, first would return nil."
But it is not empty. .isEmpty //false, So I am not understanding this.
Thanks for help in advance.
The correct way to think of Optional is that this may or may not have a value. What is the first element of an empty list? There is no such thing. It is not a value. We call that lack of a value nil or .None.
In Swift a variable must have a specific type. So your example:
let currentPlayer = players.first
What is the type of currentPlayer? It may be a String, or it may be nothing at all. It is a "maybe string" and in Swift that's called an Optional<String>. Whether players has elements or doesn't have elements doesn't change the type of currentPlayer.
If you want to do something if-and-only-if the variable has a value, then there are many ways. The simplest is if-let.
let players = ["tob", "cindy", "mindy"] //["tob", "cindy", "mindy"]
print(players.isEmpty) // False
if let currentPlayer = players.first {
print(currentPlayer)
}
This will print tob as you're expecting.
Another very common approach is the guard let
let players = ["tob", "cindy", "mindy"] //["tob", "cindy", "mindy"]
guard let currentPlayer = players.first else { return }
print(currentPlayer)
This lets you avoid nesting the rest of your function inside of curly braces, but otherwise is the same approach.
It is possible to convert an Optional into its underlying type using !, but this is very dangerous and should be avoided except where absolutely necessary. Tools like if-let and guard-let (and also Optional.map) are almost always preferred.
But the key here is to understand that all Swift variables have a single type, and sometimes that type is "maybe it has a value, maybe it doesn't."
If we look at the description of first, we will see that it always returns optional type:
public var first: Self.Generator.Element? { get }

Cannot convert value of type '[String]?' to expected argument type 'String'

What I want to do is set the image of firstCard to be equal to the image file with the name corresponding to firstCardString.
For instance, in the case below, the code could be setting self.firstCard.image to show the image named "card1" if it randomly picks it (I've clipped the rest of the array for brevity, the full thing contains 52 objects).
var deckArray = [
"card1": ["Bear","Ball"],
"card2": ["Bear","Ball"],
"card3": ["Bear","Ball"],
"card4": ["Bear","Ball"],
"card5": ["Bear","Ball"],
"card6": ["Bear","Ball"],
"card7": ["Bear","Ball"],
]
let firstRandomNumber = Int(arc4random_uniform(52))+1
let firstCardString = deckArray["card\(firstRandomNumber)"]
self.firstCard.image = UIImage(named: firstCardString)
Instead, I'm getting the following error:
Cannot convert value of type '[String]?' to expected argument type 'String'
I'm not entirely sure what this error message means, what is [String]??
[] is an array, and ? is an optional. Your firstCardString is not a string at all, but an optional array of strings. You've read the deckArray dictionary's value for that card, you see, and so your firstCardString actually looks something like this: Optional(["Bear", "Ball"]). I think you meant:
self.firstCard.image = UIImage(named: "card\(firstRandomNumber)")
This will set the image based on strings like "card1" or "card4". I assume you'll use your dictionary for something else, later. When you do, be sure to unwrap the optional value it returns:
if let cardArray = deckArray["card\(firstRandomNumber)"] {
//do something with bears and balls
}
Alternatively, consider making deckArray an array (which will make the name more reasonable), rather than a dictionary. Then you won't have to deal with optionals and will be able to access items as follows:
let cardArray = deckArray[firstRandomNumber]
//do something with bears and balls
Your deckArray is a Dictionary, and your firstCardString is an Array.
String = String
[String] = Array of strings.
It seems like deckArray is in fact, a dictionary of arrays of strings. Therefore if firstRandomNumber = 1, deckArray["card\(firstRandomNumber)"] will return ["Bear","Ball"]. That is definitely not a string!

(String: AnyObject) does not have a member named 'subscript'

I've been through similar questions but still do not understand why my code is throwing an error.
var dict = [String:AnyObject]()
dict["participants"] = ["foo", "bar"]
dict["participants"][0] = "baz"
The error is on line 3: (String: AnyObject) does not have a member named 'subscript'
I'm setting the participants key to an array and then trying to update the first element of it without any luck. The code above is shortened for example purposes, but I am using [String:AnyObject] because it is not only arrays that are stored in the dictionary.
It's probably something really trivial but I am still new to Swift. Thanks for any help in advance!
The error message tells you exactly what the problem is. Your dictionary values are typed as AnyObject. I know you know that this value is a string array, but Swift does not know that; it knows only what you told it, that this is an AnyObject. But AnyObject can't be subscripted (in fact, you can't do much with it at all). If you want to use subscripting, you need to tell Swift that this is not an AnyObject but rather an Array of some sort (here, an array of String).
There is then a second problem, which is that dict["participants"] is not in fact even an AnyObject - it is an Optional wrapping an AnyObject. So you will have to unwrap it and cast it in order to subscript it.
There is then a third problem, which is that you can't mutate an array value inside a dictionary in place. You will have to extract the value, mutate it, and then replace it.
So, your entire code will look like this:
var dict = [String:AnyObject]()
dict["participants"] = ["foo", "bar"]
var arr = dict["participants"] as [String] // unwrap the optional and cast
arr[0] = "baz" // now we can subscript!
dict["participants"] = arr // but now we have to write back into the dict
Extra for experts: If you want to be disgustingly cool and Swifty (and who doesn't??), you can perform the mutation and the assignment in one move by using a define-and-call anonymous function, like this:
var dict = [String:AnyObject]()
dict["participants"] = ["foo", "bar"]
dict["participants"] = {
var arr = dict["participants"] as [String]
arr[0] = "baz"
return arr
}()

Array as a dictionary value in swift language

I have the following swift dictionary
var List = [
2543 : [ "book", "pen" ],
2876 : [ "school", "house"]
]
How can i access the array values ?
println(List[2543][0])
The above code gives error "could not find member subscript"
and it should print "book"
Note that subscript returns an optional. We have to force unwrapping:
println(list[2543]![0])
Or use optional chaining
println(list[2543]?[0])
println(list[2543]![0])
Remember, dictionary subscript returns an Optional, not an array or whatever is inside the dictionary value.
Just try with following code:
var dic = List[0];
println("values \(dic)")
OR
println(list[2543]![0])