Сортировка словаря по значениям в 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
}