How to sort a dictionary based on keys and sort its respective values in Swift - swift

I have a dictionary with string as key and an array of int as values , i need to sort the dictionary based on keys and the array value should also be sorted.
var dicNumArray : Dictionary<String , [Int]> = ["q":[4,3,2,1,5],"a":[2,3,4,5,5],"s":[123,123,132,43,4],"t":[0,88,66,542,321]]
The result i need is the dictionary itself where it is sorted by keys and respective values are also sorted.

You can apply sorted to each the value of the key-value pair of a dictionary using mapValues
And then, you can just use sorted with a predicate comparing the keys of the dictionary.
let result = dicNumArray.mapValues { $0.sorted() }
.sorted { $0.key < $1.key }
This will return an array of key-value pair tuples.
Since, dictionaries can't be trusted with order, working with an array of the key-value pairs is the next best approach.
We can use .key and .value to get the respective values.
result.first?.key // First key
result.first?.value // First value

Dictionaries don't have an order in Swift. Having said that, you can do something like this
var dicNumArray : Dictionary<String , [Int]> = ["q":[4,3,2,1,5],"a":[2,3,4,5,5],"s":[123,123,132,43,4],"t":[0,88,66,542,321]]
func sortData() {
for (key, value) in dicNumArray {
dicNumArray[key] = value.sorted(by: { $0 < $1 })
}
}
sortData()
This will sort array for each key. Once that's done, you can do something like
let keys = Array(dicNumArray.keys).sorted(by: { $0 < $1 })
This will give you a sorted array of dictionary keys. You can test it as follows
TEST
for key in keys {
print("\(key): \(dicNumArray[key]!)")
}
OUTPUT
a: [2, 3, 4, 5, 5]
q: [1, 2, 3, 4, 5]
s: [4, 43, 123, 123, 132]
t: [0, 66, 88, 321, 542]

you can apply sort key , then map to sorted by array
let sortedKeysAndValues = dicNumArray.sorted(by: {$0.0 < $1.0}).map { [$0.key:$0.value.sorted(by: <)]}.flatMap({$0})

Related

Swift unable to sort Dictionary by Value [String: Int]

I created a Dictionary with the Userid and the timestamp from my Database. Unfortunately, the results which I store in a new dictionary are always in the same order. If I print the key and value out, and there it's right.
Here is my Code:
func sortUsers(){
let sorted = someProtocol.sorted {$0.value > $1.value} // or {$0.value < $1.value} to sort using the dictionary values
sortedValues.removeAll()
for (idx,element) in sorted.enumerated(){
let value = element.value
let key = element.key
self.sortedValues[key] = value
print("sorted Key and Value", sorted.key, sorted.value
if idx == sorted.endIndex-1{
self.downloadUserProfile(sortedValues: sortedValues)
print("sorted", sortedValues)
}
}
}
Output of first print:
sorted key and value vhsIe0nBBWQ0D9csBpLwgL4Mf293 9999999
sorted key and value ZYpiuLBRJkcM1cK6tDctKYva7UB3 9999998
output of dict:
sorted ["ZYpiuLBRJkcM1cK6tDctKYva7UB3": 9999998, "vhsIe0nBBWQ0D9csBpLwgL4Mf293": 9999999]
You can use an array of tuples instead of a dictionary
var arr = [("CCC", 333), ("DDD",444), ("AAA",222), ("BBB", 111)]
arr.sort { return $0.1 < $1.1 }

Use Dictionary for Table Data Swift

I've a dictionary that changes dependent on the user's selected options. It could be for example:
["Item1": 7, "Item2": 4, "Item3": 4, "Item4": 7, "Item5": 6]
The number next to each Item is the count for each item. I want to know how I can convert this dictionary into a table? So in the left hand column is the item and in the right hand column is the item count?
What's the best way to do this?
The data is originally an array with format: ["Item1", "Item2", "Item3", "Item1", "Item1", "Item2"].
But I used
var counts: [String: Int] = [:] , myArray.forEach { counts[$0, default: 0] += 1 }
to count each item in the array
You can transform your dictionary into a sorted array like this:
let array = data.map { $0 }.sorted { $0.key < $1.key }
This will result in an array of (key: String, value: Int) sorted alphabetically by the keys.
Now, in your tableView delegate methods you can return array.count to get the number, and if you want to configure your cell you can do something like this:
let element = array[indexPath.row]
cell.textLabel.text = element.key
cell.detailLabel.text = "\(element.value)"
So, for a tableview data source, you want an array.
var dic = ["Item1": 7, "Item2": 4, "Item3": 4, "Item4": 7, "Item5": 6]
var tableInfo = [(String, Int)]()
for (k, v) in dic {
let temp = (k, v)
tableInfo.append(temp)
}
Revised per OP's comments.
Now you have an array of tuples suitable for sorting and use in your tableview delegate.

How to sort dictionary by value?

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"] })

Split dictionaries in two array and sort the dictionary by value swift

1) this is first step : I'm asking how to make this dictionary in order by value.
2)second step: I want to split this dictionary in two array, one for value and one for keys thanks
["fruit": 1, "vegie": 13, "money": 46, "Canada": 219, "cash": 1, "lola": 1, "tv": 2, "bed": 1, "sofa": 1]
I did something like that but I want to split in two arrays now
let byValue = {
(elem1:(key: String, val: Int), elem2:(key: String, val: Int))->Bool in
if elem1.val < elem2.val {
return true
} else {
return false
}
}
let sortedDict = dict.sort(byValue)
Assuming that the part 1 of your question is done as you said in your last edit, here is how to have...
The keys:
let keys = sortedDict.map { $0.0 }
And the values:
let values = sortedDict.map { $0.1 }

Sort Dictionary by Key Value

let dict: [String:Int] = ["apple":5, "pear":9, "grape":1]
How do you sort the dictionary based on the Int value so that the output is:
sortedDict = ["pear":9, "apple":5, "grape":1]
Current Attempt (doesn't sort correctly):
let sortedDict = sorted(dict) { $0.1 > $1.1 }
You need to sort your dictionary values, not your keys. You can create an array of tuples from your dictionary sorting it by its values as follow:
Xcode 9 • Swift 4 or Xcode 8 • Swift 3
let fruitsDict = ["apple": 5, "pear": 9, "grape": 1]
let fruitsTupleArray = fruitsDict.sorted{ $0.value > $1.value }
fruitsTupleArray // [(.0 "pear", .1 9), (.0 "apple", .1 5), (.0 "grape", .1 1)]
for (fruit,votes) in fruitsTupleArray {
print(fruit,votes)
}
fruitsTupleArray.first?.key // "pear"
fruitsTupleArray.first?.value // 9
To sort your dictionary using your keys
let fruitsTupleArray = fruitsDict.sorted{ $0.key > $1.key }
fruitsTupleArray // [(key "pear", value 9), (key "grape", value 1), (key "apple", value 5)]
To sort your dictionary using its keys and localized comparison:
let fruitsTupleArray = fruitsDict.sorted { $0.key.localizedCompare($1.key) == .orderedAscending }
edit/update:
We can also extend Sequence protocol and implement a custom sort that takes a predicate and sort using a keypath property as long as it conforms to Comparable:
extension Sequence {
func sorted<T: Comparable>(_ predicate: (Element) -> T, by areInIncreasingOrder: ((T,T)-> Bool) = (<)) -> [Element] {
sorted(by: { areInIncreasingOrder(predicate($0), predicate($1)) })
}
}
Usage:
let sortedFruitsAscending = fruitsDict.sorted(\.value)
print(sortedFruitsAscending)
let sortedFruitsDescending = fruitsDict.sorted(\.value, by: >)
print(sortedFruitsDescending)
This will print
[(key: "grape", value: 1), (key: "apple", value: 5), (key: "pear", value: 9)]
[(key: "pear", value: 9), (key: "apple", value: 5), (key: "grape", value: 1)]
edit/update:
For Xcode 13 or later you can use a new generic structure called KeyPathComparator:
let fruitsTupleArray = fruitsDict.sorted(using: KeyPathComparator(\.value, order: .reverse))
Dictionaries can't be sorted. Generally, when I need things sorted from a dictionary, I will make a separate array of my dictionary keys.
In your case, make an array of the keys, sort them by comparing their values in the dictionary.
It can be achieved by using the below implementation
let sortedDictionary = unsortedDictionary.sorted{$0.key > $1.key}
use KeyValuePairs instead of Dictionary
"The order of key-value pairs in a dictionary is stable between mutations but is otherwise unpredictable. If you need an ordered collection of key-value pairs and don’t need the fast key lookup that Dictionary provides, see the KeyValuePairs type for an alternative." - Swift Dictionary