Swift: Convert Array of Dictionaries to Array of String based on a key - swift

Following is my Array of Dictionaries and I want to get an Array of only strings based on particular key (contentURL key in my case).
How can I achieve it? I have came across Reduce & Filter but no one fits into my requirement.
(
{
contentURL = "https://d1shcqlf263trc.cloudfront.net/1510232473240ab.mp4";
},
{
contentURL = "https://d1shcqlf263trc.cloudfront.net/151021804847312.mp4";
},
{
contentURL = "https://d1shcqlf263trc.cloudfront.net/151021536556612.mp4";
},
{
contentURL = "https://d1shcqlf263trc.cloudfront.net/151021528690312.mp4";
}
)
Expected Output
[
"https://d1shcqlf263trc.cloudfront.net/1510232473240ab.mp4",
"https://d1shcqlf263trc.cloudfront.net/151021804847312.mp4",
"https://d1shcqlf263trc.cloudfront.net/151021536556612.mp4",
"https://d1shcqlf263trc.cloudfront.net/151021528690312.mp4"
]

Just use compactMap
let array = arrayOfDicts.compactMap {$0["contentURL"] }

var myDict: [[String : String]] = [["contentURL" : "https://d1shcqlf263trc.cloudfront.net/1510232473240ab.mp4"],["contentURL" : "https://d1shcqlf263trc.cloudfront.net/1510232473240ab.mp4"],["contentURL" : "https://d1shcqlf263trc.cloudfront.net/1510232473240ab.mp4"]]
let arr = myDict.map { $0["contentURL"] }

var stringArray:[String] = []
for (key, value) in yourArrayOfDictionary {
stringArray.append(value)
}

var arrayDict = [["contentURL":"fd"],["contentURL":"fda"],["contentURL":"fdb"],["contentURL":"fdc"]]
let arraywithOptionstring = arrayDict.map{$0["contentURL"]}
if let arr = arraywithOptionstring as? [String]{
print(arr)
}
Expected Output : ["fd", "fda", "fdb", "fdc"]

If you want to use reduce:
let arr = [
["contentURL" : "https://d1shcqlf263trc.cloudfront.net/"],
["contentURL" : "https://d1shcqlf263trc.cloudfront.net/.mp4"],
["contentURL" : "https://d1shcqlf263trc.cloudfront.net/1510232473240ab.mp4"]
]
let only = arr.reduce([String]()) { (partialRes, dictionary) -> [String] in
return partialRes + [dictionary["contentURL"]!]
}
More compact version:
let compact = arr.reduce([String]()) { $0 + [$1["contentURL"]!] }
Probably you weren't able to use reduce since you need to remember that subscripting a dictionary returns an Optional that is a different type than String

Also you can use just .map in this case.
let array = arrayOfDicts.map {$0["contentURL"]! }

Related

swift using map to convert from array to dictionary

#Published private var rates = Dictionary<String, Double>()
This works
for e in res.rates {
self.rates[e.currencySymbol] = e.rate
}
This is returning 0 elements
let _ = res.rates.reduce(into: self.rates){ $0[$1.currencySymbol] = $1.rate }
What am I doing wrong?
You are getting an empty dictionary because you haven't used the result of reduce(into:_:), you need to use the result of it and set it to your rates dictionary.
self.rates = res.rates.reduce(into: self.rates) { $0[$1.currencySymbol] = $1.rate }
You are thinking that when you pass self.rates reduce will use it to fill the result but it is just the initial result, so you can even set empty dictionary [:].
self.rates = res.rates.reduce(into: [:]) { $0[$1.currencySymbol] = $1.rate }

Removing Non Duplicate Keys from Two Dictionary

I have two dictionaries in Swift with few similar values which are in dynamic mode:
dict1 = ["a1":"value 1", "b1":"value2", "c1":"value 3"]
dict2 = ["b1": "value2", "d1": "value4"]
If I want to compare these two dictionaries and want to extract only the matching keys even nested, how do I about to do that?
If you want the common keys with the value in one of them :
let intersectionDict = dict1.filter { dict2.keys.contains($0.key) }
//Or
let intersectionDict2 = dict2.filter { dict1.keys.contains($0.key) }
If you want the values to match too:
let intersectionDict3 = dict1.filter { dict2[$0.key] == $0.value }
And the result is:
print(intersectionDict3) //["b1": "value2"]
As others have shown, you can do this using a filter statement. You can make it even quicker by always filtering the smaller of the two dicts, improving the time complexity from O(dict1.size) to O(min(dict1.size, dict2.size).
extension Dictionary {
func intersectingByKeys(with other: Dictionary) -> Dictionary {
let (smallerDict, largerDict) = (self.count < other.count) ? (self, other) : (other, self)
return smallerDict.filter { key, _ in largerDict.keys.contains(key) }
}
}
let dict1 = ["a1":"value 1", "b1":"value2", "c1":"value 3"]
let dict2 = ["b1": "value2", "d1": "value4"]
print(dict1.intersectingByKeys(with: dict2))
You can create a Set from the keys of one of the dictionaries and call intersection on the Set with the keys of the other dictionary.
let matchingKeys = Set(dict1.keys).intersection(dict2.keys) // {"b1"}

Sort array of dictionaries based on key and value

Been playing around the high order functions lately,
and i thought of a case and i don't know if this is even possible,
consider the case below.
StringDictionary - typealias StringDictionary = [String: String]
var Group: [StringDictionary] = [
["Key1":"val2"],
["Key4":"val4"],
["Key3":"val3"],
["Key5":"val5"],
["Key2":"val1"],
]
I want to reorder this array of dictionaries to be like this.
Expected Result
var Result = [
["Key1":"val1"],
["Key2":"val2"],
["Key3":"val3"],
["Key4":"val4"],
["Key5":"val5"],
]
Using High order functions
typealias StringDictionary = [String: String]
var Group: [StringDictionary] = [
["Key1":"val2"],
["Key4":"val4"],
["Key3":"val3"],
["Key5":"val5"],
["Key2":"val1"],
]
let keys = Group.map { Array($0.keys) }.reduce([String]()) { $0 + $1 }.sorted()
let values = Group.map { Array($0.values) }.reduce([String]()) { $0 + $1 }.sorted()
let dict = Dictionary(uniqueKeysWithValues: zip(keys, values))
let newGroup:[StringDictionary] = dict.map { [$0:$1] }.sorted{ $0.keys.first! < $1.keys.first! }
print(newGroup)

Loop through array issue in swift

I have an array in which there are two values coming. I want to get them out of an array and pass the value according to index base to var1 and var2. I am looping through the array but when run the app it does not come inside the for loop. I have used break points also but it does not come inside the loop.
Code I have tried,
let myarray = UserDefaults.standard.stringArray(forKey: "selectArray") ?? [String]()
for (index, value) in myarray.enumerated() {
print("\(index): \(value)")
if index == 0{
listItem = value
print(listItem)
}else
{
CuisineItem = value
print(CuisineItem)
}
}
How can I get the value out now in two separate variables?
How you set array in UserDefaults. Look here my code works well
var array1: [[String]] = [[String]]()
array1 = [["key1", "val2"],["key2", "val2"]]
UserDefaults.standard.set(array1, forKey: "selectArray")
let myarray = UserDefaults.standard.value(forKey: "selectArray") as? [[String]]
for (index, value) in (myarray?.enumerated())! {
for (index, value) in value.enumerated() {
print("\(index): \(value)")
if index == 0 {
listItem = value
print(listItem)
}else {
CuisineItem = value
print(CuisineItem)
}
}
}
As you have mentioned that your array is of 2-D so , you can try code given below :
for oneDArray in myarray {
for(index,value) in oneDArray.enumerated(){
print("\(index1): \(value1)")
if index == 0{
listItem = value
print(listItem)
}
else {
CuisineItem = value
print(CuisineItem)
}
}
}
It should be noted that myarray is two-dimensional array , and oneDArray is one-dimensional array.
You can easily save and retrieve multi dimensional array in user defaults. Try the below code in XCode Playground, it works like a charm.
import Foundation
let array = [["a", "b", "c"], ["a", "b", "c"]];
func testArray() {
UserDefaults.standard.setValue(array, forKey: "test");
guard let testArray = UserDefaults.standard.array(forKey: "test") as? [[String]] else {
return
};
print(testArray)
}
testArray()

How do I add more items to this type of name value pair array? [duplicate]

I have a simple Dictionary which is defined like:
var dict : NSDictionary = [ 1 : "abc", 2 : "cde"]
Now I want to add an element into this dictionary: 3 : "efg"
How can I append 3 : "efg" into this existing dictionary?
You're using NSDictionary. Unless you explicitly need it to be that type for some reason, I recommend using a Swift dictionary.
You can pass a Swift dictionary to any function expecting NSDictionary without any extra work, because Dictionary<> and NSDictionary seamlessly bridge to each other. The advantage of the native Swift way is that the dictionary uses generic types, so if you define it with Int as the key and String as the value, you cannot mistakenly use keys and values of different types. (The compiler checks the types on your behalf.)
Based on what I see in your code, your dictionary uses Int as the key and String as the value. To create an instance and add an item at a later time you can use this code:
var dict = [1: "abc", 2: "cde"] // dict is of type Dictionary<Int, String>
dict[3] = "efg"
If you later need to assign it to a variable of NSDictionary type, just do an explicit cast:
let nsDict = dict as! NSDictionary
And, as mentioned earlier, if you want to pass it to a function expecting NSDictionary, pass it as-is without any cast or conversion.
you can add using the following way and change Dictionary to NSMutableDictionary
dict["key"] = "value"
I know this might be coming very late, but it may prove useful to someone.
So for appending key value pairs to dictionaries in swift, you can use updateValue(value: , forKey: ) method as follows :
var dict = [ 1 : "abc", 2 : "cde"]
dict.updateValue("efg", forKey: 3)
print(dict)
SWIFT 3 - XCODE 8.1
var dictionary = [Int:String]()
dictionary.updateValue(value: "Hola", forKey: 1)
dictionary.updateValue(value: "Hello", forKey: 2)
dictionary.updateValue(value: "Aloha", forKey: 3)
So, your dictionary contains:
dictionary[1: Hola, 2: Hello, 3: Aloha]
If your dictionary is Int to String you can do simply:
dict[3] = "efg"
If you mean adding elements to the value of the dictionary a possible solution:
var dict = Dictionary<String, Array<Int>>()
dict["key"]! += [1]
dict["key"]!.append(1)
dict["key"]?.append(1)
Swift 3+
Example to assign new values to Dictionary. You need to declare it as NSMutableDictionary:
var myDictionary: NSMutableDictionary = [:]
let newValue = 1
myDictionary["newKey"] = newValue
print(myDictionary)
For whoever reading this for swift 5.1+
// 1. Using updateValue to update the given key or add new if doesn't exist
var dictionary = [Int:String]()
dictionary.updateValue("egf", forKey: 3)
// 2. Using a dictionary[key]
var dictionary = [Int:String]()
dictionary[key] = "value"
// 3. Using subscript and mutating append for the value
var dictionary = [Int:[String]]()
dictionary[key, default: ["val"]].append("value")
In Swift, if you are using NSDictionary, you can use setValue:
dict.setValue("value", forKey: "key")
Given two dictionaries as below:
var dic1 = ["a": 1, "c": 2]
var dic2 = ["e": 3, "f": 4]
Here is how you can add all the items from dic2 to dic1:
dic2.forEach {
dic1[$0.key] = $0.value
}
Dict.updateValue updates value for existing key from dictionary or adds new new key-value pair if key does not exists.
Example-
var caseStatusParams: [String: AnyObject] = ["userId" : UserDefault.userID ]
caseStatusParams.updateValue("Hello" as AnyObject, forKey: "otherNotes")
Result-
▿ : 2 elements
- key : "userId"
- value : 866
▿ : 2 elements
- key : "otherNotes"
- value : "Hello"
[String:Any]
For the fellows using [String:Any] instead of Dictionary below is the extension
extension Dictionary where Key == String, Value == Any {
mutating func append(anotherDict:[String:Any]) {
for (key, value) in anotherDict {
self.updateValue(value, forKey: key)
}
}
}
As of Swift 5, the following code collection works.
// main dict to start with
var myDict : Dictionary = [ 1 : "abc", 2 : "cde"]
// dict(s) to be added to main dict
let myDictToMergeWith : Dictionary = [ 5 : "l m n"]
let myDictUpdated : Dictionary = [ 5 : "lmn"]
let myDictToBeMapped : Dictionary = [ 6 : "opq"]
myDict[3]="fgh"
myDict.updateValue("ijk", forKey: 4)
myDict.merge(myDictToMergeWith){(current, _) in current}
print(myDict)
myDict.merge(myDictUpdated){(_, new) in new}
print(myDict)
myDictToBeMapped.map {
myDict[$0.0] = $0.1
}
print(myDict)
To add new elements just set:
listParameters["your parameter"] = value
There is no function to append the data in dictionary. You just assign the value against new key in existing dictionary. it will automatically add value to the dictionary.
var param = ["Name":"Aloha","user" : "Aloha 2"]
param["questions"] = "Are you mine?"
print(param)
The output will be like
["Name":"Aloha","user" : "Aloha 2","questions" : ""Are you mine"?"]
To append a new key-value pair to a dictionary you simply have to set the value for the key. for eg.
// Initialize the Dictionary
var dict = ["name": "John", "surname": "Doe"]
// Add a new key with a value
dict["email"] = "john.doe#email.com"
print(dict)
Output -> ["surname": "Doe", "name": "John", "email": "john.doe#email.com"]
var dict = ["name": "Samira", "surname": "Sami"]
// Add a new enter code herekey with a value
dict["email"] = "sample#email.com"
print(dict)
Up till now the best way I have found to append data to a dictionary by using one of the higher order functions of Swift i.e. "reduce". Follow below code snippet:
newDictionary = oldDictionary.reduce(*newDictionary*) { r, e in var r = r; r[e.0] = e.1; return r }
#Dharmesh In your case, it will be,
newDictionary = dict.reduce([3 : "efg"]) { r, e in var r = r; r[e.0] = e.1; return r }
Please let me know if you find any issues in using above syntax.
Swift 5 happy coding
var tempDicData = NSMutableDictionary()
for temp in answerList {
tempDicData.setValue("your value", forKey: "your key")
}
I added Dictionary extension
extension Dictionary {
func cloneWith(_ dict: [Key: Value]) -> [Key: Value] {
var result = self
dict.forEach { key, value in result[key] = value }
return result
}
}
you can use cloneWith like this
newDictionary = dict.reduce([3 : "efg"]) { r, e in r.cloneWith(e) }
if you want to modify or update NSDictionary then
first of all typecast it as NSMutableDictionary
let newdictionary = NSDictionary as NSMutableDictionary
then simply use
newdictionary.setValue(value: AnyObject?, forKey: String)