I have a dictionary:
var dictionary: [String: Any] = ["test1": "one", "test2": "two", "test3": 3, "test4": 4]
What is the best way to get a new dictionary, but only with String values?
You can write an extension for Dictionary:
extension Dictionary where Key == String, Value: Any {
var withoutInt: [String: Any] {
return self.filter{ $0.value is String }
}
}
And then use it:
dictionary = dictionary.withoutInt
How about this:
for (key, value) in dictionary {
if let value = value as? Int {
dictionary.removeValue(forKey: key)
}
}
Pseudo steps:
1.) Check each key/value pair in the dictionary
2.) Check if the value is an Integer
3.) If value is an integer, remove dictionary value associated with that key for that pair
Caveat: This is modifying your original dictionary. If you wanted to create a new (second instance) of your dictionary and keep the original intact, I think this would be as simple as creating a new dictionary and assigning it to the values of the original, then modifying the second dictionary instead.
You can just filter those that are numbers.
Get those that are strings.
dictionary = dictionary.filter({ ($0.value as? Int) == nil })
Get those that are Ints
dictionary = dictionary.filter({ ($0.value as? Int) != nil })
All we do here are filter by cast typing to Int and seeing if it is nil or not.
Note: Could just do to original dictionary --
var dictionary: [String: Any] = ["test1": "one", "test2": "two", "test3": 3, "test4": 4].filter({ ($0.value as? Int) == nil })
OR
var dictionary: [String: Any] = ["test1": "one", "test2": "two", "test3": 3, "test4": 4].filter({ ($0.value as? Int) != nil })
for (key, value) in dictionary {
if let v = value as? Int {
dictionary.removeValue(forKey : key)
}
}
if you don't modify parent dictionary then
func removeInt(dictionary : [String : Any]) ->[String : Any] {
var dict2 = NSMutableDictionary()
for (key, value) in dictionary {
if let v = value as? Int {
dict2.setValue(v, forKey : key)
}
}
return (dict2 as! [String : Any])
}
Related
In a given Dictionary, I need to find a nested Dictionary ([String : Any]) for a given key.
The general structure of the Dictionary (e.g. nesting levels, value types) is unknown and given dynamically. [1]
Inside of this sub-Dictionary, there is a given value for the key "value" (don't ask) which needs to be fetched.
Here's an example:
let theDictionary: [String : Any] =
[ "rootKey" :
[ "child1Key" : "child1Value",
"child2Key" : "child2Value",
"child3Key" :
[ "child3SubChild1Key" : "child3SubChild1Value",
"child3SubChild2Key" :
[ "comment" : "child3SubChild2Comment",
"value" : "child3SubChild2Value" ]
],
"child4Key" :
[ "child4SubChild1Key" : "child4SubChild1Value",
"child4SubChild2Key" : "child4SubChild2Value",
"child4SubChild3Key" :
[ "child4SubChild3SubChild1Key" :
[ "value" : "child4SubChild3SubChild1Value",
"comment" : "child4SubChild3SubChild1Comment" ]
]
]
]
]
With brute force and pseudo memoization, I managed to hack a function together that iterates through the entire Dictionary and fetches the value for a given key:
func dictionaryFind(_ needle: String, searchDictionary: Dictionary<String, Any>) -> String? {
var theNeedleDictionary = Dictionary<String, Any>()
func recurseDictionary(_ needle: String, theDictionary: Dictionary<String, Any>) -> Dictionary<String, Any> {
var returnValue = Dictionary<String, Any>()
for (key, value) in theDictionary {
if value is Dictionary<String, Any> {
if key == needle {
returnValue = value as! Dictionary<String, Any>
theNeedleDictionary = returnValue
break
} else {
returnValue = recurseDictionary(needle, theDictionary: value as! Dictionary<String, Any>)
}
}
}
return returnValue
}
// Result not used
_ = recurseDictionary(needle, theDictionary: searchDictionary)
if let value = theNeedleDictionary["value"] as? String {
return value
}
return nil
}
This works so far. (For your playground testing pleasure:
let theResult1 = dictionaryFind("child3SubChild2Key", searchDictionary: theDictionary)
print("And the result for child3SubChild2Key is: \(String(describing: theResult1!))")
let theResult2 = dictionaryFind("child4SubChild3SubChild1Key", searchDictionary: theDictionary)
print("And the result for child4SubChild3SubChild1Key is: \(String(describing: theResult2!))")
let theResult3 = dictionaryFind("child4Key", searchDictionary: theDictionary)
print("And the result for child4Key is: \(String(describing: theResult3))")
).
My question here:
What would be a more clean, concise, "swifty", way to iterate through the Dictionary and - especially - break completely out of the routine as soon the needed key has been found?
Could a solution even be achieved using a Dictionary extension?
Thanks all!
[1] A KeyPath as described in Remove nested key from dictionary therefor isn't feasible.
A more compact recursive solution might be:
func search(key:String, in dict:[String:Any], completion:((Any) -> ())) {
if let foundValue = dict[key] {
completion(foundValue)
} else {
dict.values.enumerated().forEach {
if let innerDict = $0.element as? [String:Any] {
search(key: key, in: innerDict, completion: completion)
}
}
}
}
the usage is:
search(key: "child3SubChild2Key", in: theDictionary, completion: { print($0) })
which gives:
["comment": "child3SubChild2Comment", "value": "child3SubChild2Subchild1Value"]
alternatively, if you don't want to use closures, you might use the following:
extension Dictionary {
func search(key:String, in dict:[String:Any] = [:]) -> Any? {
guard var currDict = self as? [String : Any] else { return nil }
currDict = !dict.isEmpty ? dict : currDict
if let foundValue = currDict[key] {
return foundValue
} else {
for val in currDict.values {
if let innerDict = val as? [String:Any], let result = search(key: key, in: innerDict) {
return result
}
}
return nil
}
}
}
usage is:
let result = theDictionary.search(key: "child4SubChild3SubChild1Key")
print(result) // ["comment": "child4SubChild3SubChild1Comment", "value": "child4SubChild3SubChild1Value"]
The following extension can be used for finding values of a key in nested dictionaries, where different levels each can contain the same key associated with a different value.
extension Dictionary where Key==String {
func find<T>(_ key: String) -> [T] {
var keys: [T] = []
if let value = self[key] as? T {
keys.append(value)
}
self.values.compactMap({ $0 as? [String:Any] }).forEach({
keys.append(contentsOf: $0.find(key))
})
return keys
}
}
I some optionals: numberOfApples:Int?, numberOfBananas:Int?, numberOfOlives:Int? and I'd like to create a dictionary of just the set values. Is there way do succinctly create this?
The closest I've got is:
// These variables are hard-coded for the example's
// sake. Assume they're not known until runtime.
let numberOfApples: Int? = 2
let numberOfBananas: Int? = nil
let numberOfOlives: Int? = 5
let dict: [String:Int?] = ["Apples" : numberOfApples,
"Bananas" : numberOfBananas,
"Olives" : numberOfOlives]
And I'd like to dict to be of type: [String:Int] like so:
["Apples" : 2,
"Olives" : 5]
But this gives me a dictionary of optionals and accessing a value by subscripting gives my a double-wrapped-optional.
I realise that I could do this with a for-loop, but I was wondering if there's something more elegant.
Many thanks in advance.
Personally I would do it this way (and it's how I personally do this when it comes up):
var dict: [String: Int] = [:]
dict["Apples"] = numberOfApples
dict["Bananas"] = numberOfBananas
dict["Olives"] = numberOfOlives
Simple. Clear. No tricks.
But if you wanted to, you could write Dictionary.flatMapValues (to continue the pattern of Dictionary.mapValues). It's not hard. (EDIT: Added flattenValues() to more closely match original question.)
extension Dictionary {
func flatMapValues<T>(_ transform: (Value) throws -> T?) rethrows -> [Key: T] {
var result: [Key: T] = [:]
for (key, value) in self {
if let transformed = try transform(value) {
result[key] = transformed
}
}
return result
}
func flattenValues<U>() -> [Key: U] where Value == U? {
return flatMapValues { $0 }
}
}
With that, you could do it this way, and that would be fine:
let dict = [
"Apples" : numberOfApples,
"Bananas": numberOfBananas,
"Olives" : numberOfOlives
].flattenValues()
You can use filter and mapValues. You first filter all pairs where the value is not nil and then you can safely force unwrap the value. This will change the dict type to [String: Int].
let dict = [
"Apples": numberOfApples,
"Bananas": numberOfBananas,
"Olives": numberOfOlives
]
.filter({ $0.value != nil })
.mapValues({ $0! })
print(dict) //["Olives": 5, "Apples": 2]
Try this:
let numberOfApples: Int? = 5
let numberOfBananas: Int? = nil
let numberOfOlives: Int? = 5
let dict: [String: Int?] = [
"Apples": numberOfApples,
"Bananas": numberOfBananas,
"Olives": numberOfOlives
]
extension Dictionary {
func flatMapValues<U>() -> [Key: U] where Value == Optional<U> {
return reduce(into: [:]) { $0[$1.key] = $1.value }
// Keeping this line as it provides context for comments to this answer. You should delete it if you copy paste this.
// return filter { $0.value != nil } as! [Key : U]
}
}
let unwrappedDict = dict.flatMapValues()
let foo: Int?? = dict["Apples"]
let bar: Int? = unwrappedDict["Apples"]
I'd like to build a dictionary of dictionaries. In Swift how do I declare a dictionary with a key of a String and the value of a dictionary of this same type? I need to be able to have potentially infinite nests. (Kind of like building a tree using nodes. Except it's not a tree, it's a dictionary.)
I tried using AnyObject, but get a conversion error:
var node1: Dictionary<String, AnyObject?> = ["foo" : nil]
var node2: Dictionary<String, AnyObject?> = ["bar" : node1] // ERROR: Cannot convert value of type 'Dictionary<String, AnyObject?>' (aka 'Dictionary<String, Optional<AnyObject>>') to expected dictionary value type 'Optional<AnyObject>'
Is there a type-safe way of doing this (i.e., not using AnyObject?)
You can achieve something like this with a nice API and type safety in swift by using a struct and an enumeration.
enum RecursiveDictValue<KeyType: Hashable, ValueType> {
case Value(ValueType)
case Dict(RecursiveDict<KeyType, ValueType>)
}
struct RecursiveDict<KeyType: Hashable, ValueType> {
typealias OwnType = RecursiveDict<KeyType, ValueType>
private var dict: [KeyType: RecursiveDictValue<KeyType, ValueType>]
init() {
dict = [:]
}
init(dict: [KeyType: RecursiveDictValue<KeyType, ValueType>]) {
self.dict = dict
}
// this ensures that we can safely chain subscripts
subscript(key: KeyType) -> OwnType {
get {
switch dict[key] {
case let .Dict(dict)?:
return dict
default:
return RecursiveDict<KeyType, ValueType>()
}
}
set(newValue) {
dict[key] = .Dict(newValue)
}
}
subscript(key: KeyType) -> ValueType? {
get {
switch dict[key] {
case let .Value(value)?:
return value
default:
return nil
}
}
set(newValue) {
if let newValue = newValue {
dict[key] = RecursiveDictValue<KeyType, ValueType>.Value(newValue)
} else {
dict[key] = nil
}
}
}
}
This works quite nicely (note that you need to help swift with the types though):
var dict = RecursiveDict<String, Int>(dict: ["value":.Value(1),
"dict":.Dict(RecursiveDict<String, Int>(dict: ["nestedValue": .Value(2)]))])
if let value: Int = dict["value"] {
print(value) // prints 1
}
if let value: Int = dict["dict"]["nestedValue"] {
print(value) // prints 2
}
It also fails as intended when you do stuff that can't work.
if let value: Int = dict["dict"] {
print(value) // is not executed
}
if let value: Int = dict["dict"]["nestedDict"]["nestedValue"] {
print(value) // is not executed
}
And you can even set values in nested dictionaries that haven't been created yet!:
dict["dict"]["nestedDict2"]["nestedValue"] = 3
if let value: Int = dict["dict"]["nestedDict2"]["nestedValue"] {
print(value) // prints 3
}
I was working with firebase, and i needed to achieve an structure similar to this:
["llave3": ["hola": "", "dos": ""], "llave1": ["hola": "", "dos": ""], "llave2": ["hola": "", "dos": ""]]
This is a nested dictionary, or a dictionary of dictionaries. I achieve this by simply doing this:
var array = ["llave1", "llave2","llave3"]
var dictOfDictionarys = [String : [String : String]] ()
for items in array {
dictOfDictionarys[items] = ["hola":"","dos":""]
}
Very less info.. and you mean infinite nested dictionaries? I dont think so..
func returnDict() -> Dictionary<String, AnyObject> {
return ["Got You" : returnDict()]
}
var x : Dictionary<String, AnyObject> = ["GotYou" : returnDict()]
Just saying, nothing better can happen to this other than a crash
this is a case of infinite recursion. When you have infinite dictionaries, it doesnt mean that it is going to run forever. It means that it is going to run till your device runs out of memory. A call to function returnDict, calls returnDict, which again calls returnDict and so on.
A recursion is basically adding a method onto the stack of pre-existing stack of methods in memory.. this can happen until the stack overflows. Hence, stackOverFlow
let node1: Dictionary<String, AnyObject!> = ["foo" : nil]
var node2 = ["bar" : node1]
Playground approves of it
The reason is that like in Objective-C values in the Dictionary type must be non-optional.
It's not very useful anyway because in Swift assigning a nil value to a key removes the key.
var node1: Dictionary<String, AnyObject> = ["foo" : "Hello"]
var node2: Dictionary<String, AnyObject> = ["bar" : node1]
If I declare an enum like this:
enum Keys {
case key_one
case key_two
}
I can print it and it will be automatically converted to a String:
print(Keys.key_one) // prints "key_one"
If I then make a dictionary that maps Strings to whatever (but let's choose Strings again for simplicity), I think that it should be able to add a key by using Keys.key_one as the key, right? Wrong.
var myDict = [String : String]()
/// error: cannot subscript a value of type '[String : String]' with an index
/// of type 'Keys'
myDict[Keys.key_one] = "firstKey"
I can do it if I explicitly convert Keys.key_one to a String like this though:
myDict[String(Keys.key_one)] = "firstKey"
print(myDict) // ["key_one": "firstKey"]
So I want to do this without having to wrap my enum with String() every time.
I've tried a few things by doing an extension off of Dictionary using the where keyword with the Key and trying to implement new subscript functions, but I can't get it to work. What's the trick?
Update and improvement for Swift 4.2
extension Dictionary {
subscript(key: APIKeys) -> Value? {
get {
guard let key = key.stringValue as? Key else { return nil }
return self[key]
}
set(value) {
guard let key = key.stringValue as? Key else { return }
guard let value = value else { self.removeValue(forKey: key); return }
self.updateValue(value, forKey: key)
}
}
}
protocol APIKeys {}
extension APIKeys {
var stringValue: String {
return String(describing: self)
}
}
enum Keys: APIKeys {
case key_one
case key_two
}
var myStringDict = [AnyHashable : Any]()
var model1StringDict = [String : Any]()
var model2StringDict = [String : String]()
myStringDict.updateValue("firstValue", forKey: Keys.key_one.stringValue) // [key_one: firstValue]
myStringDict[Keys.key_two] = "secondValue" // [key_two: secondValue, key_one: firstValue]
myStringDict[Keys.key_one] = nil // [key_two: secondValue]
myStringDict.removeValue(forKey: Keys.key_two.stringValue) // []
model1StringDict.updateValue("firstValue", forKey: Model1Keys.model_1_key_one.stringValue) // [model_1_key_one: firstValue]
model1StringDict[Model1Keys.model_1_key_two] = "secondValue" // [model_1_key_two: secondValue, model_1_key_one: firstValue]
model1StringDict[Model1Keys.model_1_key_one] = nil // [model_1_key_two: secondValue]
model2StringDict.updateValue("firstValue", forKey: Model2Keys.model_2_key_one.stringValue) // [model_2_key_one: firstValue]
model2StringDict[Model2Keys.model_2_key_two] = "secondValue" // [model_2_key_two: secondValue, model_2_key_one: firstValue]
model2StringDict[Model2Keys.model_2_key_one] = nil // [model_2_key_two: secondValue]
I specifically changed the types of the 3 dictionaries to show the common ways of typing a dictionary ([AnyHashable : Any], [String : Any], and [String : String]), and showed that this works with each of the types.
It's important to note that if you use updateValue instead of the assignment operator when the key of your dictionary is AnyHashable, then you need to specify the String value of the key with .stringValue. Otherwise, the exact type of the key being stored will not explicitly be a String, and it'll get messed up later if you try to, say, remove a value under your key via assigning nil to that key. For a dictionary where the key is specifically typed to be String, then the updateValue function will have a compile time error saying that the key needs to be a String, so you can't mess it up that way.
Swift 2.3
I figured out the extension solution that I wanted.
extension Dictionary {
subscript(key: Keys) -> Value? {
get {
return self[String(key) as! Key]
}
set(value) {
guard
let value = value else {
self.removeValueForKey(String(key) as! Key)
return
}
self.updateValue(value, forKey: String(key) as! Key)
}
}
}
enum Keys {
case key_one
case key_two
}
var myStringDict = [String : String]()
/// Adding the first key value through the String() way on purpose
myStringDict.updateValue("firstValue", forKey: String(Keys.key_one))
// myStringDict: ["key_one": "firstValue"]
// myStringDict[Keys.key_one]!: firstValue
myStringDict[Keys.key_two] = "secondValue"
// myStringDict: ["key_one": "firstValue", "key_two": "secondValue"]
myStringDict[Keys.key_one] = nil
// myStringDict: ["key_two": "secondValue"]
Notice that the declared dictionary key type is String, but I'm able to just use Keys.key_one and the subscript in the dictionary extension takes care of the rest.
I can probably put some better guarding around the as! conversion to Key, but I'm not sure it's needed, as I know that my enum can always be converted to a valid Key by the String() cast.
Improvement to answer
Even better, since I'm using this for API Keys, I made a blank protocol called APIKeys and each model will implement their own Keys enum that conforms to the APIKeys protocol. And the dictionary's subscript is updated to take in APIKeys as the Key value.
extension Dictionary {
subscript(key: APIKeys) -> Value? {
get {
return self[String(key) as! Key]
}
set(value) {
guard
let value = value else {
self.removeValueForKey(String(key) as! Key)
return
}
self.updateValue(value, forKey: String(key) as! Key)
}
}
}
protocol APIKeys {}
enum Keys: APIKeys {
case key_one
case key_two
}
enum Model1Keys: APIKeys {
case model_1_key_one
case model_1_key_two
}
enum Model2Keys: APIKeys {
case model_2_key_one
case model_2_key_two
}
var myStringDict = [String : String]()
var model1StringDict = [String : String]()
var model2StringDict = [String : String]()
myStringDict.updateValue("firstValue", forKey: String(Keys.key_one)) // myStringDict: ["key_one": "firstValue"]
myStringDict[Keys.key_two] = "secondValue" // myStringDict: ["key_one": "firstValue", "key_two": "secondValue"]
myStringDict[Keys.key_one] = nil // myStringDict: ["key_two": "secondValue"]
model1StringDict.updateValue("firstValue", forKey: String(Model1Keys.model_1_key_one)) // model1StringDict: ["model_1_key_one": "firstValue"]
model1StringDict[Model1Keys.model_1_key_two] = "secondValue" // model1StringDict: ["model_1_key_one": "firstValue", "model_1_key_two": "secondValue"]
model1StringDict[Model1Keys.model_1_key_one] = nil // model1StringDict: ["model_1_key_two": "secondValue"]
model2StringDict.updateValue("firstValue", forKey: String(Model2Keys.model_2_key_one)) // model2StringDict: ["model_2_key_one": "firstValue"]
model2StringDict[Model2Keys.model_2_key_two] = "secondValue" // model2StringDict: ["model_2_key_one": "firstValue", "model_2_key_two": "secondValue"]
model2StringDict[Model2Keys.model_2_key_one] = nil // model2StringDict: ["model_2_key_two": "secondValue"]
Or you can do:
enum Keys: String {
case key_one
case key_two
}
And use it like this:
var myDict = [String : String]()
myDict[Keys.key_one.rawValue] = "firstKey"
Update
If you really want to make it work, you can do as below. But these is some risks by forcing the unwrapping.
extension Dictionary where Key: StringLiteralConvertible {
subscript (key: Keys) -> Value? {
get {
return self[key.rawValue as! Key]
}
set {
self[key.rawValue as! Key] = newValue
}
}
}
And then you use it like this:
myDict[Keys.key_one] = "firstKey"
myDict[Keys.key_one]
How important is it that your keys are Strings? If it's not important, I suggest doing something like:
enum Keys {
case key_one
case key_two
}
var myDict = [Keys : String]()
myDict[Keys.key_one] = "firstKey"
print(myDict) // [Keys.key_one: "firstKey"]
Say I have the following dictionary ["Lionel Messi":"170cm"]
Would it be possible to find that key-value pair if i only knew part of key string. In other words, would it be possible to find the above mentioned key-value pair if i only had the string "Lione".
func findPartOfString(partOfKey: String, myDict: Dictionary) -> String {
for (key, value) in myDict {
if key.containsString(partOfKey) {
return value
}
}
return null
}
EDIT:
Here's a new shorter way with Swift2:
func findPartOfString(partOfKey: String, myDict: Dictionary) -> String {
for (key, value) in myDict where key.containsString(partOfString) {
return value
}
return null
let filter = "Lionel"
let dict = ["Lionel Messi" : "170cm", "Me" : "Taller"]
let result = dict.keys.filter { $0.containsString(filter) }
if let first = result.first {
print("match found: (\(first) => \(dict[first]!))")
}
Outputs
match found: (Lionel Messi => 170cm)