I have an array of dictionaries called arrayOfDict which contains a number of dictionary objects all with the same keys: QUESTIONID and OPTIONID.
[ //arrayOfDict
{QUESTIONID:1, OPTIONID:0},
{QUESTIONID:2, OPTIONID:201},
{QUESTIONID:3, OPTIONID:204)
];
I need to add such dictionaries to arrayOfDict only if the dictionary I am adding does not contain the same QUESTIONID. If the QUESTIONID already exists then the corresponding OPTIONID needs to be replaced with new one. How can I compare my QUESTIONID with the QUESTIONID in arrayOfDict ?
you can try to get the index of the same question dic, if you get it, remove, else just insert it, try this:
if let index = array.index(where: {$0["QUESTIONID"] == dic["QUESTIONID"]}) {
array.remove(at: index)
}
array.append(dic)
Please check :
var dict = arrayOfDict.map { dictionary -> ([String : Int]) in
var dicti = dictionary
if dicti["QUESTIONID"] == 1 { // You can change 1 with whatever `QUESTIONID` you want to check
dicti["OPTIONID"] = 1 // You can change 1 with whatever value you want to assign for `OPTIONID`
}
return dicti
}
print(dict)
Related
I have a dictionary that holds objects, inside that objects I have an id, is there a way to check matches with this id and return the object?
example:
if I have id = 2 and I want to check if there exists in the object and get the particular object that matches with this id
Thanks for the help
my structs:
struct CoinsInfo:Codable {
let data:[String:CoinSpecificInfo]?
}
struct CoinSpecificInfo:Codable {
let urls:UrlsCoins?
let logo:String?
let id:Int?
let symbol:String?
}
You can try
// item is an instance of CoinsInfo
// get a new dictionary with all keys that has id matching in their value
guard let matches = item.data?.filter { $1.id == 2 } else { return }
// get an array of objects
let arr = Array(matches.values)
I'm trying to figure out the best way in Swift to add values to an Array that is a Value in a Dictionary. I want to build a dictionary of contacts sorted by the first letter of their first name. For example [A : [Aaron, Adam, etc...], B : [Brian, Brittany, ect...], ...]
I found this function:
updateValue(_:forKey:)
And tried using it in a loop:
for contact in self.contacts.sorted() {
self.contactDictionary.updateValue([contact], forKey: String(describing: contact.characters.first))
}
But when I tried to use that it replaced the existing array with a new one. I know I can manually check to see if the key in the dictionary exists, if it does, retrieve the array and then append a new value, otherwise add the new key/value pair but I'm not sure if Swift provides an easier/better way to do this.
Any insight would be much appreciated!
You can use reduce(into:) method (Swift4) and as follow:
let contacts = ["Aaron", "Adam", "Brian", "Brittany", ""]
let dictionary = contacts.reduce(into: [String:[String]]()) { result, element in
// make sure there is at least one letter in your string else return
guard let first = element.first else { return }
// create a string with that initial
let initial = String(first)
// initialize an array with one element or add another element to the existing value
result[initial] = (result[initial] ?? []) + [element]
}
print(dictionary) // ["B": ["Brian", "Brittany"], "A": ["Aaron", "Adam"]]
If you are using Swift3 or earlier you would need to create a mutable result dictionary inside the closure:
let contacts = ["Aaron", "Adam", "Brian", "Brittany", ""]
let dictionary = contacts.reduce([String:[String]]()) { result, element in
var result = result
guard let first = element.first else { return result }
let initial = String(first)
result[initial] = (result[initial] ?? []) + [element]
return result
}
print(dictionary) // ["B": ["Brian", "Brittany"], "A": ["Aaron", "Adam"]]
Note that the result is not sorted. A dictionary is an unordered collection. If you need to sort your dictionary and return an array of (key, Value) tuples you can use sorted by key as follow:
let sorted = dictionary.sorted {$0.key < $1.key}
print(sorted)
"[(key: "A", value: ["Aaron", "Adam"]), (key: "B", value: ["Brian", "Brittany"])]\n"
Swift 4's new dictionary initializers can do it all for you:
let contactInitials = contacts.filter{!$0.isEmpty}.map{ ($0.first!,[$0]) }
let dict = [Character:[String]](contactInitials, uniquingKeysWith:+)
I'm trying to figure out the best way in Swift to add values to an Array that is a Value in a Dictionary. I want to build a dictionary of contacts sorted by the first letter of their first name. For example [A : [Aaron, Adam, etc...], B : [Brian, Brittany, ect...], ...]
I found this function:
updateValue(_:forKey:)
And tried using it in a loop:
for contact in self.contacts.sorted() {
self.contactDictionary.updateValue([contact], forKey: String(describing: contact.characters.first))
}
But when I tried to use that it replaced the existing array with a new one. I know I can manually check to see if the key in the dictionary exists, if it does, retrieve the array and then append a new value, otherwise add the new key/value pair but I'm not sure if Swift provides an easier/better way to do this.
Any insight would be much appreciated!
You can use reduce(into:) method (Swift4) and as follow:
let contacts = ["Aaron", "Adam", "Brian", "Brittany", ""]
let dictionary = contacts.reduce(into: [String:[String]]()) { result, element in
// make sure there is at least one letter in your string else return
guard let first = element.first else { return }
// create a string with that initial
let initial = String(first)
// initialize an array with one element or add another element to the existing value
result[initial] = (result[initial] ?? []) + [element]
}
print(dictionary) // ["B": ["Brian", "Brittany"], "A": ["Aaron", "Adam"]]
If you are using Swift3 or earlier you would need to create a mutable result dictionary inside the closure:
let contacts = ["Aaron", "Adam", "Brian", "Brittany", ""]
let dictionary = contacts.reduce([String:[String]]()) { result, element in
var result = result
guard let first = element.first else { return result }
let initial = String(first)
result[initial] = (result[initial] ?? []) + [element]
return result
}
print(dictionary) // ["B": ["Brian", "Brittany"], "A": ["Aaron", "Adam"]]
Note that the result is not sorted. A dictionary is an unordered collection. If you need to sort your dictionary and return an array of (key, Value) tuples you can use sorted by key as follow:
let sorted = dictionary.sorted {$0.key < $1.key}
print(sorted)
"[(key: "A", value: ["Aaron", "Adam"]), (key: "B", value: ["Brian", "Brittany"])]\n"
Swift 4's new dictionary initializers can do it all for you:
let contactInitials = contacts.filter{!$0.isEmpty}.map{ ($0.first!,[$0]) }
let dict = [Character:[String]](contactInitials, uniquingKeysWith:+)
I'm trying to show a tableview similar to contacts with my list of users.
I declare a global variable of friends that will store the first character of a name and a list of users whose first name start with that
var friends = [Character: [User]]()
In my fetch method, I do this
for friend in newFriends {
let letter = friend.firstName?[(friend.firstName?.startIndex)!]
print(letter)
self.friends[letter!]?.append(friend)
}
After this, I should have my friends array with the first letter of the name and the users that fall in it; however, my friends dictionary is empty.
How do I fix this?
Edit: I'm following this tutorial and he doesnt exactly the same.. Swift: How to make alphabetically section headers in table view with a mutable data source
Rather than using Character as the key, use String. You need to be sure to init the [User] array for every new First Initial key you insert into groupedNames. I keep an array of groupedLetters to make it easier to get a section count
var groupedNames = [String: [User]]()
var groupedLetters = Array<String>()
func filterNames() {
groupedNames.removeAll()
groupedLetters.removeAll()
for friend in newFriends {
let index = friend.firstName.index(friend.firstName.startIndex, offsetBy: 0)
let firstLetter = String(friend.firstName[index]).uppercased()
if groupedNames[firstLetter] != nil {
//array already exists, just append
groupedNames[firstLetter]?.append(friend)
} else {
//no array for that letter key - init array and store the letter in the groupedLetters array
groupedNames[firstLetter] = [friend]
groupedLetters.append(firstLetter)
}
}
}
Creating a Dictionary structure with Characters as keys & values as Array of User will be more succinct.
The error occurs because you are declaring an empty dictionary, that means you have to add a key / empty array pair if there is no entry for that character.
Consider also to consolidate the question / exclamation marks
class User {
let firstName : String
init(firstName : String) {
self.firstName = firstName
}
}
var friends = [Character: [User]]()
let newFriends = [User(firstName:"foo"), User(firstName:"bar"), User(firstName:"baz")]
for friend in newFriends {
let letter = friend.firstName[friend.firstName.startIndex]
if friends[letter] == nil {
friends[letter] = [User]()
}
friends[letter]!.append(friend)
}
If I have a Dictionary returned from a NSNotification containing the following
print(notificationObj.object)
Optional({
age = "<null>";
names = (
David
);
})
Then the guard else is called when trying to assign this to a variable:
guard let categories = notificationObj.object as? [String:[String]] else {
// Gets to here
return
}
How can I handle the case where a Dictionary key is null.
Your dictionary does contain ...
Optional({
age = "<null>";
names = (
David
);
})
... and ...
age = ... is String = String (value is single String),
names = ( ... ) is String = [String] (value is array of Strings).
You can't cast it to [String:[String]] because the first pair doesn't fit this type. This is the reason why your guard statement hits else.
Hard to answer your question. Dictionary contains names, you want categories, names key does contain David, which doesn't look like category, ... At least you know why guard hits else.
Your questions is not very clear.
However IF
You have a dictionary declared as follow [String:[String]]
And you want manage the scenario where a given key is not present
Like this
let devices : [String:[String]] = [
"Computers": ["iMac", "MacBook"],
"Phones": ["iPhone 6S", "iPhone 6S Plus"]
]
Then you can at least 2 solutions
1. conditional unwrapping
if let cars = devices["Car"] {
// you have an array of String containing cars here
} else {
print("Ops... no car found")
}
2. guard let
func foo() {
guard let cars = devices["Car"] else {
print("Ops... no car found")
return
}
// you have an array of String containing cars here...
cars.forEach { print($0) }
}
It appears that your printed notificationObject.object is constructed from a JSON string that looks like this:
"{ \"age\": null, \"names\":[\"David\"] }"
The reason that you are hitting your else clause is because age is actually a nil, and not a valid String array. I tried using [String: [String]?] and [String: NSArray?] neither of which seem to work. The type is actually an NSNull (which inherits from NSObject).
So you can cast to [String: AnyObject] and check for NSArray like this:
if let categories = j as? [String: AnyObject] where (categories["age"] is NSArray) {
print("age was array")
} else {
print("age is probably null")
}
You might be better off if your notification object simply omitted the "age" property when the value is null. Then you would be able to cast to [String: [String]].