I have a problem concerning my nested dictionary.
var level1Dictionary = [String : [String : String]]()
var ChosenDeckLabel = [String]
textview.text
I want to see if the dictionary contains a certain value within my, else if statement as such:
else if level1Dictionary[ChosenDeckLabel[textview.text]] != nil {
this returns error:
Cannot subscript value of type String with an index of type String!
How should I cast it to check if the nested dictionary contains the value?
Dictionaries are optionals by default because they are not sure if a key/value pair exist. Be sure to include your "!" AND "?" to wrap and unwrap your data being passed.
Arrays offer subscripting via integers and ranges as seen in Swift's API:
public subscript (index: Int) -> Element
public subscript (subRange: Range<Int>) -> ArraySlice<Element>
You're trying to subscript via a string which is throwing the error. You need to get the index of the element in the array and then use that to subscript the array to get the value: e.g.
let dictOfDicts = [String : [String : String]]()
var arrayOfStrings: [String] = ["a", "b", "c"]
let stringToCheck = "a"
dictOfDicts["a"] = ["some": "thing"]
if let index = array.indexOf(stringToCheck) {
if dictOfDicts[array[Int(index)]] != nil {
// do something
}
}
I think this is what you intend to do:
else if level1Dictionary[strIndex1][strIndex2] != nil {
When you are doing this:
level1Dictionary[ChosenDeckLabel[textview.text]]
you are trying to access the ChosenDeckLabel array using a String subscript:
ChosenDeckLabel[textview.text]
which is not a valid operation. Arrays are Int indexed and not string indexed.
Related
I have an array that holds dictionaries whose value is an array of dictionary whose value is an array of strings. Each key of each the dictionary is a String. the structure is like so:
[String : [String : [String]]]
I am trying to get the value of the array at the index like so:
for index in 0...arrayCount {
let thisValue = myArray[index]
}
where myArray represents the array of dictionaries in question.
However, I get the error message:
Cannot subscript a value of type '[String : [String : [String]]]' with an index of type 'Int'
I would think that saying let thisValue = myArray[index] would assign thisValue to be a dictionary of the form String : [String : [String]]
Can anyone explain I might be doing incorrectly and how I can access the value at index?
Your data type declaration:
[String: [String : [String]]]
Indicates that you have a Dictionary of Dictionaries with the final entries being arrays of strings.
So since all of your dictionaries uses String for keys, using a Int would indeed generate an error.
If you want to extract the Dictionary of arrays, you would need something similar to:
// let sourceData: [String: [String: [String]]] ...
guard
let myArrayOfDict: [String: [String]] = sourceData["some valid root key"],
let myArray: [String] = myArrayOfDict["Some other key"]
else { /* oops, those keys didn't match anything! */ return }
for index in 0..<myArray.count {
let thisValue = myArray[index]
}
for myString in myArray {
// myString is a "String"
}
I am getting a JSON from an API. So, I want to store a particular value with key SKU. So, what I did was:
var skuArr = [""]
{ (response, error) in
if (error != nil)
{
print("Error \(error.debugDescription)")
}
else
{
self.coinsArr = response.arrayObject as? Array<Dictionary<String, Any>>
for i in 0 ..< (self.coinsArr?.count)!
{
self.skuArr = [response[i]["sku"].rawValue as! String]
}
}
So, with this I am getting the array in skuArr, but when i is 0 I am getting ["a"], and when i is 1 I want it to be ["a","b"], but it gives ["b"] only and when the loop ends with only the last value and not with ["a","b","c","d"] which I want as the final result. How can I insert each of them in the Array?
First of all declare skuArr as empty string array.
var skuArr = [String]()
And this is Swift. There are better ways than ugly index based loops to extract data for example with map or compactMap
if let result = response.arrayObject as? Array<Dictionary<String, Any>> {
self.coinsArr = result
self.skuArr = result.compactMap{ $0["sku"] as? String }
}
And why is coinsArr declared as optional as you are going to force unwrap it anyway? It's highly recommended to use non-optional types as much as possible. Non-optionals can never cause a well-liked unexpected found nil crash
Don't use this:
self.skuArr = [response[i]["sku"].rawValue as! String]
As this will replace the previous value with new one.
Use .append to insert into array.
self.skuArr.append([response[i]["sku"].rawValue as! String])
EDIT
change your initialisation as below:
skuArr: [String] = []
TLDR: Trying to create a dictionary with type [String]/[Any] with Key containing arrays of mixed data types. Then trying to loop through and create a new dict with just the Key and Bool Value results in a force cast error.
Thanks in advance for the help!
Long version:
I have 4 arrays I need to convert (2 String, 1 Bool, 1 Int) into a dictionary. I created a dictionary with the Key of type String and the Value of type Any as I need one of the String arrays to be the Key and the rest to be contained in an array as the Value. Like this:
var dict1: [String: [Any]] = [:]
Then I loop through the previously mentioned arrays and create key/value pairs:
Edit: i = 0
//i-1 to match iteration with array position
while i < dict1.count {
i += 1
dict1[stringArray1[i-1]] = [intArray[i-1], boolArray[i-1], stringArray2[i-1]]
}
When I print the dictionary, it contains the correct Key/Value pairs.
Now I need to create a dictionary with just the Key from dict1 and Bool array values from the key. So I've set up an empty array like this:
var dict2: [String: [Bool]] = [:]
and tried to create KeyValue pairs like this:
for (string, bool) in dict1 {
dict2[string] = bool
}
I get an error saying I need to force cast to type Bool. Force casting to type Bool creates an error saying swift can't convert an Int to a Bool. I tried changing the type of the Key in dict2 to type Int, and got an error saying to forecast to type Int. Doing so says Swift can't force Bool to Int.
EDIT:
this will help you with cast
var dict2: [String: [Bool]] = [:]
var dict1: [String: [Any]] = ["a" : [1], "b" : [true], "c": [false], "d" : ["e"]]
for (string, bool) in dict1 {
dict2[string] = bool.flatMap({$0 as? Bool})
}
This is an example how can you filter and cast [string:any] dictionary to [string:bool]
let dict: [String : Any] = ["a" : 1, "b" : true, "c": false]
let casted = dict.filter{$0.value is Bool}.reduce([String: Bool]()) { (dictionary, nextValue) -> [String: Bool] in
var mutableDictionary = dictionary
mutableDictionary[nextValue.key] = nextValue.value as? Bool
return mutableDictionary
}
I think there will be no problem for you to follow this and cast [String:[Any]] to [String:[Bool]]
I have a dictionary/array, looks like this:
var myArray: [[String:NSObject]] = []
let newItem = [
[
"caseNumber" : caseToAdd,
"formType" : formType,
"caseStatus" : caseStatus,
"caseDetails" : caseDetails,
"caseLUD" : caseLUD,
"friendlyName" : ""
]]
//Add new item to existing array
myArray += newItem
This works fine, I can access the items etc. But now I want to save it to NSUserDefaults so I can access it again in the future. I can save it just fine, but trying to load it again is giving me an issue:
myArray = HelperSavedData().loadMyCasesFromNSUserDefaults
Here is the HelperSavedData class:
public class HelperSavedData {
let defaults = NSUserDefaults.standardUserDefaults()
public func saveMyCasesToNSUserDefaults(input:NSObject){
defaults.setObject(input, forKey: "myArray")
defaults.synchronize()
}
public func loadMyCasesFromNSUserDefaults() -> [[String:NSObject]]? {
if let savedArray = defaults.valueForKey("myArray") {
return ((savedArray) as! [[String : NSObject]])
}
return nil
}
}
But I am getting the error:
Cannot assign value of type () -> [[String: NSObject]]? to type [[String: NSObject]]
You can't assign an optional type to a non-optional type without some amount of unwrapping.
You've defined myArray as being a non-optional array of dictionaries.
var myArray: [[String:NSObject]] = []
The variable, myArray can never be nil.
You've defined loadMyCasesFromNSUserDefaults() as returning an optional array of dictionaries.
public func loadMyCasesFromNSUserDefaults() -> [[String:NSObject]]?
That is to say, this method could return nil.
So we have to decide what makes most sense in terms of how to handle our variables. Does it make sense to allow nil to be assign into our myArray variable? If so, make it an optional as other answers suggest:
var myArray: [[String:NSObject]]?
But maybe it never makes sense for myArray to be nil. In this case, don't change the declaration of myArray. Instead, determine how we handle the case in which your method returns nil.
We could say... we only want to assign into myArray if we load a non-nil array from the method:
var myArray = [[String:NSObject]]()
if let loadedArray = loadMyCasesFromNSUserDefaults() {
myArray = loadedArray
}
myArray += newItem
Or we could use the Nil-Coalescing operator and assign a default value into myArray if loadMyCasesFromNSUserDefaults() returns nil.
var myArray = loadMyCasesFromNSUserDefaults() ?? [newItem]
And there are plenty of other ways to deal with nil and optionals as well.
What is key here, is we need to make a few decisions.
Should myArray ever allowed to be nil? Does that make sense?
If myArray shouldn't be nil, what makes sense for handling the case in which our method returns nil? How do we want to handle that?
You're returning an optional value from loadMyCasesFromNSUserDefaults() and trying to save it in a non-optional value. Try changing the myArray declaration like this
var myArray: [[String:NSObject]]?
loadMyCasesFromNSUserDefaults() return [[String:NSObject]]? which is an optional value ,pls try var myArray?: [[String:NSObject]] = []
I'm using Parse and I have an array of PFObjects called "scorecardData". Each PFObject has a "score" property that is of type Int. I'm trying to sort my array by "score" but I'm getting the following error: "Binary operator '<' cannot be applied to two 'AnyObject?' operands". I'm not sure what I'm doing wrong here. I also tried down casting the objectForKey("score") as! Int but its not letting me do this. Any suggestions? Thanks in advance.
var scorecardData = [PFObject]()
scorecardData.sortInPlace({$0.objectForKey("score") < $1.objectForKey("score")})
You declared scorecardData variable as Array of PFObject. Why are you trying access PFObject property using objectForKey: reserved? Anyway I am not parse expert. But if you declared your array as [PFObject] you can use:
scorecardData.sortInPlace({$0.score < $1.score})
But this won't work unless you subclass PFObject for a more native object-oriented class structure. If you do that remember also to specify:
var scorecardData = [YOUR_NEW_CLASS]()
I strongly recommend subclassing PFObject to make use of all swift type-safe goodies.
But if you want to keep your data structure you can use:
scorecardData.sortInPlace({($0["score"] as! Int) < ($1["score"] as! Int)})
Keep in mind that it's dangerous, and in future avoid it.
If you want to Sort your array of PFOject... You can do this
extension Array where Element:PFObject {
func sort() -> [PFObject] {
return sort { (first, second) -> Bool in
let firstDate = first.objectForKey("time") as! NSDate//objectForKey(Constants.Parse.Fields.User.fullName) as? String
let secondDate = second.objectForKey("time") as! NSDate//objectForKey(Constants.Parse.Fields.User.fullName) as? String
return firstDate.compare(secondDate) == .OrderedAscending
}
}
}
Have you tried doing this?
var query = PFQuery(className:"ScoreCard")
// Sorts the results in ascending order by the score field
query.orderByDescending("score")
query.findObjectsInBackgroundWithBlock {