Сортировка словаря по значениям в Swift
Есть ли аналоговые ключи - (NSArray * )SortedByValueUsingSelector: (SEL) в swift?
Как это сделать без кастования в NSDictionary?
Я пробовал это, но, похоже, это не очень хорошее решение.
var values = Array(dict.values)
values.sort({
$0 > $1
})
for number in values {
for (key, value) in dict {
if value == number {
println(key + " : \(value)");
dict.removeValueForKey(key);
break
}
}
}
Пример:
var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
dict.sortedKeysByValues(>) // fanta (12), cola(10), sprite(8)
Ответы
Ответ 1
Try:
let dict = ["a":1, "c":3, "b":2]
extension Dictionary {
func sortedKeys(isOrderedBefore:(Key,Key) -> Bool) -> [Key] {
return Array(self.keys).sort(isOrderedBefore)
}
// Slower because of a lot of lookups, but probably takes less memory (this is equivalent to Pascals answer in an generic extension)
func sortedKeysByValue(isOrderedBefore:(Value, Value) -> Bool) -> [Key] {
return sortedKeys {
isOrderedBefore(self[$0]!, self[$1]!)
}
}
// Faster because of no lookups, may take more memory because of duplicating contents
func keysSortedByValue(isOrderedBefore:(Value, Value) -> Bool) -> [Key] {
return Array(self)
.sort() {
let (_, lv) = $0
let (_, rv) = $1
return isOrderedBefore(lv, rv)
}
.map {
let (k, _) = $0
return k
}
}
}
dict.keysSortedByValue(<)
dict.keysSortedByValue(>)
Обновлено:
Обновлен для синтаксиса нового массива и семантики сортировки из бета-версии 3. Обратите внимание, что я использую sort
, а не sorted
, чтобы свести к минимуму копирование массива. Код можно было бы сделать более компактным, посмотрев более раннюю версию и заменив sort
на sorted
и установив KeyType[]
как [KeyType]
Обновлен до Swift 2.2:
Изменены типы от KeyType
до Key
и ValueType
до Value
. Использованный новый sort
встроенный в Array
вместо sort(Array)
Примечание. Производительность для всех из них может быть немного улучшена с помощью sortInPlace
вместо sort
Ответ 2
Вы можете использовать что-то вроде этого, возможно:
var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
var myArr = Array(dict.keys)
var sortedKeys = sort(myArr) {
var obj1 = dict[$0] // get ob associated w/ key 1
var obj2 = dict[$1] // get ob associated w/ key 2
return obj1 > obj2
}
myArr // ["fanta", "cola", "sprite"]
Ответ 3
Это должно дать вам отсортированные ключи на основе значения и немного более чистым:
var sortedKeys = Array(dict.keys).sorted({dict[$0] < dict[$1]})
Ответ 4
Я думаю, что это самый простой способ сортировать словарь Swift по значению.
let dict = ["apple":1, "cake":3, "banana":2]
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)
Ответ 5
Сортировка ваших ключей по значению словаря на самом деле проще, чем сначала:
let yourDict = ["One": "X", "Two": "B", "Three": "Z", "Four": "A"]
let sortedKeys = yourDict.keys.sort({ (firstKey, secondKey) -> Bool in
return yourDict[firstKey] < yourDict[secondKey]
})
И это! Там действительно ничего более. Мне еще предстоит найти более быстрый метод.
Ответ 6
Множество ответов, здесь однострочный. Мне это нравится, потому что он полностью использует собственные итеративные функции Swift и не использует переменные. Это должно помочь оптимизатору сделать свою магию.
return dictionary.keys.sort({ $0 < $1 }).flatMap({ dictionary[$0] })
Обратите внимание на использование flatMap, потому что подписка на словарь делает необязательным значение. На практике это никогда не должно возвращать нуль, поскольку мы получаем ключ от самого словаря. flatMap
существует только для того, чтобы гарантировать, что результат не является массивом опций. Если ваше связанное с массивом значение должно быть необязательным, вы можете использовать map
вместо этого.
Ответ 7
Просто добавьте его в NSDictionary, а затем вызовите метод. В любом случае, когда вы используете @selector
в ObjC, вы можете просто использовать String в Swift. Таким образом, это будет выглядеть так:
var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
let sortedKeys = (dict as NSDictionary).keysSortedByValueUsingSelector("compare:")
или
let sortedKeys2 = (dict as NSDictionary).keysSortedByValueUsingComparator
{
($0 as NSNumber).compare($1 as NSNumber)
}
Ответ 8
С Swift 3, чтобы сортировать ваши ключи на основе значений, ниже выглядит многообещающим:
var keys = Array(dict.keys)
keys.sortInPlace { (o1, o2) -> Bool in
return dict[o1]! as! Int > dict[o2]! as! Int
}
Ответ 9
OneLiner:
let dict = ["b":2,"a":1,"c":3]
(Array(dict).sorted{$0.1 < $1.1}).forEach{(k,v) in print("\(k):\(v)")}
//Output: a:1, b:2, c:3
Поменяйте .forEach
на .map
→ Функциональное программирование
Синтаксический сахар:
extension Dictionary where Value:Comparable {
var sortedByValue:[(Key,Value)] {return Array(self).sorted{$0.1 < $1.1}}
}
extension Dictionary where Key:Comparable {
var sortedByKey:[(Key,Value)] {return Array(self).sorted{$0.0 < $1.0}}
}
["b":2,"a":1,"c":3].sortedByKey//a:1, b:2, c:3
["b":2,"a":1,"c":3].sortedByValue//a:1, b:2, c:3
Ответ 10
Следующий способ в Swift 3 отсортировал мой словарь по значению в порядке возрастания:
for (k,v) in (Array(dict).sorted {$0.1 < $1.1}) {
print("\(k):\(v)")
}
Ответ 11
Следующие могут быть полезны, если вы хотите, чтобы результат был массивом пар значений ключа в форме кортежа, отсортированным по значению.
var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
let sortedArrByValue = dict.sorted{$0.1 > $1.1}
print(sortedArrByValue) // output [(key: "fanta", value: 12), (key: "cola", value: 10), (key: "sprite", value: 8)]
Ответ 12
SWIFT 3:
Используя несколько ресурсов, я поставил этот красиво короткий код вместе.
dictionary.keys.sorted{dictionary[$0]! < dictionary[$1]!}
Возвращает массив ключей словаря, отсортированных по их значениям. Он отлично работает и не вызывает ошибок, когда словарь пуст. Попробуйте этот код на игровой площадке:
//: Playground - noun: a place where people can play
import UIKit
let dictionary = ["four": 4, "one": 1, "seven": 7, "two": 2, "three": 3]
let sortedDictionary = dictionary.keys.sorted{dictionary[$0]! < dictionary[$1]!}
print(sortedDictionary)
// ["one", "two", "three", "four", "seven"]
let emptyDictionary = [String: Int]()
let emptyDictionarySorted = emptyDictionary.keys.sorted{emptyDictionary[$0]! < emptyDictionary[$1]!}
print(emptyDictionarySorted)
// []
Если вам нужна помощь по поводу того, почему код использует $0, $1 и даже не имеет круглых скобок после метода сортировки, проверьте этот пост - fooobar.com/questions/78700/...
Ответ 13
Вот как я это сделал - сортировка в этом случае с помощью ключа, называемого положением. Попробуйте это на детской площадке:
var result: [[String: AnyObject]] = []
result.append(["name" : "Ted", "position": 1])
result.append(["name" : "Bill", "position": 0])
result
result = sorted(result, positionSort)
func positionSort(dict1: [String: AnyObject], dict2: [String: AnyObject]) -> Bool {
let position1 = dict1["position"] as? Int ?? 0
let position2 = dict2["position"] as? Int ?? 0
return position1 < position2
}