I need to get a sorted key list from a dictionary by their values.
I found an answer close to this question but not good enough:
extension Dictionary {
func sortedKeysByValue(by compareMethod: (Value, Value) -> Bool) -> [Key] {
return self
.sorted {
let (lk, lv) = $0
let (rk, rv) = $1
return compareMethod(lv, rv)
}
.map {
let (key, _) = $0
return key
}
}
}
let dict = ["a": 5, "b": 3, "c": 10, "d": 7, "e": 9, "f": 5]
let result = dict.keysSortedByValue(>)
// The result could be:
// ["c", "e", "d", "a", "f", "b"] or
// ["c", "e", "d", "f", "a", "b"]
The question is that: when the value is equal, it should compare the keys to always produce the same results. To do so, I need to make compareMethod
not just accept Value
type but also Key
type. I try to make the method signature use Comparable
protocol, but is gets a compilation error:
extension Dictionary where Key: Comparable, Value: Comparable {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ensure Key/Value types are Comparable
func sortedKeysByValue(by compareMethod: (Comparable, Comparable) -> Bool) -> [Key] {
^^^^^^^^^^ ^^^^^^^^^^ got error (see below)
return self
.sorted {
let (lk, lv) = $0
let (rk, rv) = $1
return compareMethod(lv, rv) || (lv == rv && compareMethod(lk, rk))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compare keys when values are equal
}
.map {
let (key, _) = $0
return key
}
}
}
Compilation error: Protocol 'Comparable' can only be used as a generic constraint because it has Self or associated type requirements
The compareMethod
should be able to handle both Value
type and Key
type. How do I fix it?