How to sort dictionary by value? - swift

My dictionary like this:
var items = [Int: [String]]()
var itemsResult = [Int: [String]]()
itmesResult stores the data downloaded from server.
and pass the data to items use of items = itmesResult
the value has 3 elements like ["Apple","/image/apple.png","29"]
and I want to sort the dictionary by first value which is Apple.
for (k,v) in (itemsResult.sorted(by: { $0.value[0] < $1.value[0] })) {
items[k] = v
}
The result of above code is not my expectation.
I would like to sort it alphabetically how can I do this?
Edit:
origin:
1:["Apple","/image/apple.png","29"]
2:["AAA","/image/aaa.png","29"]
3:["Banana","/image/banana.png","29"]
sorted:
2:["AAA","/image/aaa.png","29"]
1:["Apple","/image/apple.png","29"]
3:["Banana","/image/banana.png","29"]
I would like to sort it by first value.

So if I take your example, this does the trick:
var items = [Int: [String]]()
items[0] = ["Apple","/image/apple.png","29"]
items[1] = ["AAA","/image/aaa.png","29"]
items[2] = ["Banana","/image/banana.png","29"]
let itemResult = items.sorted { (first: (key: Int, value: [String]), second: (key: Int, value: [String])) -> Bool in
return first.value.first! < second.value.first!
}
print (itemResult)
The right thing to do is to use objects of course, and note that I'm not null checking the "first" object in each array, but this is not a problem to change.
Let me know if this is what you were looking for, the output is:
[(1, ["AAA", "/image/aaa.png", "29"]), (0, ["Apple", "/image/apple.png", "29"]), (2, ["Banana", "/image/banana.png", "29"])]
EDIT:
Also note, that this case doesn't actually "sort" the dictionary, because a dictionary is by definition not sorted, this creates an array of key-value objects sorted using the array indexes

Instead of saving these variable into an array of arrays, make them an array of dictionaries.
You can do this like so:
var dictionaries:[Dictionary<String, String>] = []
for item in items {
let dictionary = {"name": item[0], "url": item[1], "id" : item[2]}
dictionaries.append(dictionary)
}
You can get your sorted list of dictionaries like this:
dictionaries.sorted(by: { $0["name"] < $1["name"] })

Related

Add two dictionary values in new array . the array values will remains unchanged from its position

Add two dictionary values in a new array. the array values will remain unchanged from its position. I need to add two dictionary values in a new array. The values added in the array must remain constant at every run.
var dictionary1:[String:Int] = ["Mohan":75, "Raghu":82, "John":79]
var dictionary2:[String:Int] = ["Surya":91, "John":79, "Saranya":92]
dictionary1.merge(dictionary2){(current, _) in current}
var arr : [String] = []
for (key, value) in dictionary1 { arr.append("(key) (value)") }
print(dictionary1)
Simply use append(contentsOf:) to add the contents of dictionary1 and dictionary2 to arr. Use map(_:) to format the key-value pairs while adding to the array.
let dictionary1 = ["Mohan":75, "Raghu":82, "John":79]
let dictionary2 = ["Surya":91, "John":79, "Saranya":92]
var arr = [String]()
arr.append(contentsOf: dictionary1.map({"\($0.key) \($0.value)"}))
arr.append(contentsOf: dictionary2.map({"\($0.key) \($0.value)"}))
print(arr) //["Mohan 75", "John 79", "Raghu 82", "Surya 91", "John 79", "Saranya 92"]
As apple stats, you can use KeyValuePairs to maintain ordered collection of key-value pairs and don’t require the fast key lookup that the Dictionary type provides.
let recordTimes: KeyValuePairs = ["Florence Griffith-Joyner": 10.49,
"Evelyn Ashford": 10.76,
"Evelyn Ashford": 10.79,
"Marlies Gohr": 10.81]
print(recordTimes.first!)
// Prints "("Florence Griffith-Joyner", 10.49)"
Check if it is helpful in your case.

Swift, Dictionary of String:String, best way to get an array of values, where the key contains a string?

I have a dictionary, like this:
{"Matt":"Apple", "Calvin":"Nut", "Susie":"Pear"}
I want to check the keys of the dictionary with a string, to see if they contain that string-- and if they do, I want to add their respective value to an array
So, if the input was "a"
the return would be ["Apple", "Nut"] because "Matt" and "Calvin" matched the "a"
Basically looking for some Swift tips,
otherwise I was going to implement it like this:
Grab all keys, put into an array
Filter keys for string value, this is the keyArray
Enumerate over keyArray, and get all their values from the dictionary
Boom have an array of values
You can filter the dictionary, using contains() on each key,
and then extract the corresponding values:
let dict = [ "Matt":"Apple", "Calvin":"Nut", "Susie":"Pear" ]
let input = "a"
let values = Array(dict.filter { $0.key.contains(input) }.values)
print(values) // ["Apple", "Nut"]
Or with flatMap() (renamed to compactMap() in Swift 4.1):
let values = dict.flatMap { $0.key.contains(input) ? $0.value : nil }
print(values) // ["Apple", "Nut"]
Here each dictionary entry is mapped to the value if the key contains
the given string, and to nil otherwise. flatMap() then returns an
array with the non-nil values.
Simply using a filter over the dictionary:
let dict: [String: String] = ["Matt": "Apple", "Calvin": "Nut", "Susie": "Pear"]
func findValuesMatching(search: String, in dict: [String: String]) -> [String] {
return dict
.filter { (key, value) in
return key.range(of: search) != nil
}.map { (key, value) in
return value
}
}
print(findValuesMatching(search: "a", in: dict))
Do it like this:
let dict = ["Matt":"Apple", "Calvin":"Nut", "Susie":"Pear"]
let containsA = dict.filter({ $0.key.lowercased().contains("a") }).map({ $0.value })
Output:
["Apple", "Nut"]

Adding items to Array as a Dictionary Value

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:+)

How to extract a subset of a swift 3 Dictionary

I've looked through the methods here but I can't quite find what I'm looking for. I'm new-ish to Swift. I would like to extract a subset from a Dictionary based on a Set of key values, preferably without a loop.
For example, if my key Set is of type Set<String> and I have a Dictionary of type Dictionary<String, CustomObject>, I would like to create a new Dictionary of type Dictionary<String, CustomObject> that contains only the key-value pairs associated with the keys in the Set of Strings.
I can see that I could do this with for loop, by initializing a new Dictionary<String, CustomObj>(), checking if the original Dictionary contains a value at each String in the set, and adding key-value pairs to the new Dictionary. I am wondering if there is a more efficient/elegant way to do this however.
I'd be open to finding the subset with an Array of Strings instead of a Set if there is a better way to do it with an Array of keys.
Many thanks!
Swift 5 - You can do this very simply:
let subsetDict = originalDict.filter({ mySet.contains($0.key)})
The result is a new dictionary with the same type as the original but which only contains the key-value pairs corresponding to the keys in mySet.
Your assumption is correct, there is a more concise/swift-ish way to accomplish what you need.
For example you can do it via reduce, a functional programming concept available in Swift:
let subDict = originalDict.reduce([String: CustomObject]()) {
guard mySet.contains($1.key) else { return $0 }
var d = $0
d[$1.key] = $1.value
return d
}
Or, in two steps, first filtering the valid elements, and then constructing back the dictionary with the filtered elements:
let filteredDict = originalDict.filter { mySet.contains($0.key) }
.reduce([CustomObject]()){ var d = $0; d[$1.key]=$1.value; return d }
forEach can also be used to construct the filtered dictionary:
var filteredDict = [CustomObject]()
mySet.forEach { filteredDict[$0] = originalDict[$0] }
, however the result would be good it it would be immutable:
let filteredDict: [String:CustomObject] = {
var result = [String:CustomObject]()
mySet.forEach { filteredDict2[$0] = originalDict[$0] }
return result
}()
Dummy type:
struct CustomObject {
let foo: Int
init(_ foo: Int) { self.foo = foo }
}
In case you'd like to mutate the original dictionary (instead of creating a new one) in an "intersect" manner, based on a given set of keys:
let keySet = Set(["foo", "baz"])
var dict = ["foo": CustomObject(1), "bar": CustomObject(2),
"baz": CustomObject(3), "bax": CustomObject(4)]
Set(dict.keys).subtracting(keySet).forEach { dict.removeValue(forKey: $0) }
print(dict) // ["foo": CustomObject(foo: 1), "baz": CustomObject(foo: 3)]

Swift: build a dictionary with keys from array1, and values from array2

Here are 2 arrays: countriesVotedKeys and dictionnaryCountriesVotes.
I need to build a dictionary, whose keys are all the items from countriesVotedKeys, and its values are all the items from dictionnaryCountriesVotes. Both arrays contains same number of elements.
I've tried many things, but none lead to desired result.
for value in self.countriesVotedValues! {
for key in self.countriesVotedKeys! {
self.dictionnaryCountriesVotes![key] = value
}
}
I can clearly see why this code produce bad result: second array is iterated in its entirity at each iteration of first array. I also tried a classical for var i= 0, var j= 0;...... but it seems this kind of syntax is not allowed in swift.
In short, i'm stuck. Again.
Swift 4
let keys = ["key1", "key2", "key3"]
let values = [100, 200, 300]
let dict = Dictionary(uniqueKeysWithValues: zip(keys, values))
print(dict) // "[key1: 100, key3: 300, key2: 200]"
Swift 3
var dict: [String: Int] = [:]
for i in 0..<keys.count {
dict[keys[i]] = values[i]
}
Use NSDictionary's convenience initializer:
let keys = ["a", "b", "c"]
let values = [1,2,3]
var dict = NSDictionary(objects: values, forKeys: keys) as [String: Int]