web-dev-qa-db-fra.com

Trier un dictionnaire dans Swift

Je sais que ce sujet a déjà été discuté mais je ne peux pas résoudre d'autres réponses, donc désolé d'avance pour mon développement!

J'ai besoin de trier ce dictionnaire par clés

codeValueDict = ["us": "$", "it": "€", "fr": "€"]

donc j'ai besoin d'un dictionnaire comme celui-ci

sortedDict = ["fr": "€", "it": "€", "us": "$"]

mais je ne peux pas faire ça.

J'ai essayé ça 

let sortedKeysAndValues = sorted(dictionary) { $0.0 < $1.0 }

mais après j'ai besoin de créer deux tableaux de ce dictionnaire (clés et valeurs) et, en utilisant cette solution 

codesArray = sortedKeysAndValues.keys.array

donnez-moi l'erreur '[(String, String)]' n'a pas de membre nommé 'keys' car cette solution ne renvoie pas exactement un dictionnaire.

J'ai donc essayé une autre solution:

    let prova = codiceNomeDict as NSDictionary
    for (k,v) in (Array(codiceNomeDict).sorted {$0.1 < $1.1}) {
        let value = "[\"\(k)\": \"\(v)\"]"
        println(value)
    }

Ce qui fonctionne bien, mais je ne sais pas comment créer un nouveau dictionnaire de value s.

Quelle est la meilleure solution? Comment le faire fonctionner?

10
Matte.Car

La sortie de la fonction sorted ci-dessus est un Array . Donc, vous ne pouvez pas obtenir les clés et les valeurs comme un Dictionnaire . Mais vous pouvez utiliser la fonction map pour récupérer ces clés et valeurs triées

Retourne un tableau contenant les éléments triés de source {selon} . L'algorithme de tri n'est pas stable (peut changer l'ordre relatif de Éléments pour lesquels isOrderedBefore n'établit pas d'ordre).

let codeValueDict = ["us": "$", "it": "€", "fr": "€"]

let sortedArray = sorted(codeValueDict, {$0.0 < $1.0})
print(sortedArray)

let keys = sortedArray.map {return $0.0 }
print(keys)

let values = sortedArray.map {return $0.1 }
print(values)
19
Duyen-Hoa

Les dictionnaires ne sont pas commandés. Si vous voulez énumérer ces éléments dans l’ordre, vous pouvez le faire en utilisant la solution de @ HoaParis (qui est ma préférence), ou

for (k,v) in sorted(codiceNomeDict, {$0.1 < $1.1}) { ... }

ce qui est juste un peu mieux que ce que vous faisiez auparavant car il ne génère pas de tableau temporaire.

Mais si vous voulez vraiment "une collection qui mappe une valeur à une autre et qui soit ordonnée par sa clé", vous devez créer une autre structure de données pour cela. Alors faisons ça. C'est une bonne expérience d'apprentissage.

Cette version implémente simplement SequenceType et fournit un indice get/set, qui correspond à la plupart de ce que vous souhaiteriez généralement. En faire un CollectionType complet est un peu pénible à mon avis, puisque startIndex et endIndex doivent être O (1). Possible; juste plus que ce que je veux faire ce matin.

Notez l'ajout majeur de Key: Comparable. C'est pourquoi Dictionary ne peut pas être commandé. Il n'y a aucune promesse que vous pouvez trier leurs clés. En ajoutant cette exigence, nous pouvons le faire.

struct SortedDictionary<Key: Hashable, Value where Key: Comparable>: SequenceType {
    private var dict: Dictionary<Key, Value>
    init(_ dict: Dictionary<Key, Value>) {
        self.dict = dict
    }
    func generate() -> GeneratorOf<(Key, Value)> {
        let values = Array(Zip(self.dict.keys, self.dict.values))
            .sorted {$0.0 < $1.0 }
        return GeneratorOf(values.generate())
    }
    subscript(key: Key) -> Value? {
        get        { return self.dict[key] }
        set(value) { self.dict[key] = value }
    }
}

var codeValueDict = ["us": "$", "it": "€", "fr": "€"]
var sortedDict = SortedDictionary(codeValueDict)
for (k, v) in sortedDict {
    println("\(k) => \(v)")
}
sortedDict["us"]
sortedDict["ab"] = "!"
sortedDict

Pourquoi voudriez-vous vous embêter avec SortedDictionary alors que vous avez déjà sorted()? En général, je ne le ferais pas. Mais cela offre des opportunités d'abstraction. Vous pouvez contrôler l'ordre de tri lors de la création d'un objet plutôt que lors de son énumération. Vous pouvez potentiellement mettre en cache l'ordre de tri (bien que je soupçonne que dans la plupart des cas, cela fera mal plutôt que d'aider).

Mais je recommande simplement d’utiliser sorted en général.

6
Rob Napier

Swift n'inclut pas un type de dictionnaire trié et les dictionnaires ne peuvent pas être triés. Vous pouvez ajouter une extension proposant le tri à [(Key, Value)] en procédant comme suit:

extension Dictionary {

    func sort(isOrderedBefore: (Key, Key) -> Bool) -> [(Key, Value)] {
        var result: [(Key, Value)] = []
        let sortedKeys = keys.array.sorted(isOrderedBefore)
        for key in sortedKeys {
            result.append(key, self[key]!)
        }
        return result
    }
}
3
vrwim

Trier vos clés en fonction de la valeur du dictionnaire est en réalité plus simple qu'il n'y parait au début:

let yourDict = ["One": "X", "Two": "B", "Three": "Z", "Four": "A"]
let sortedKeys = yourDict.keys.sort({ (firstKey, secondKey) -> Bool in
    return yourDict[firstKey] < yourDict[secondKey]
})

Et c'est tout! Il n'y a vraiment rien de plus.

2
Martin

Vous ne pouvez pas trier le dictionnaire aussi facilement. Je pense que le dictionnaire utilise une sorte de structure de données arborescente. Mais après le tri, vous obtenez un tableau de tuples. Ainsi, vous pouvez obtenir les clés de la manière suivante:

    let codeValueDict = ["us": "$", "it": "€", "fr": "€"]
    let sortedKeysAndValues = sorted(codeValueDict) { $0.0 < $1.0 }
    let keys = sortedKeysAndValues.map {$0.0 }
    let values = sortedKeysAndValues.map {$0.1 }
2
Vasyl Khmil

Clé de tri insensible à la casse dans Swift 2

Voici une fonction qui renvoie un tableau de clés triées par respectant la casse (ou toute valeur de chaîne). 

N'oubliez pas que la structure des données du dictionnaire Swift ne peut pas être stockée, triée par clé dans la mémoire. Alors oui, vous pouvez le trier par clé, mais si vous l’imprimez par exemple, l’ordre des touches est à nouveau aléatoire.

 /// returns an array of values sorted by values case-insensitive
func sortCaseInsensitive(values:[String]) -> [String]{

    let sortedValues = values.sort({ (value1, value2) -> Bool in

        if (value1.lowercaseString < value2.lowercaseString) {
            return true
        } else {
            return false
        }
    })
    return sortedValues
}

Appeler avec 

    let dict = ["world": "Hello!", "foo": "bar", "zYeah": "a", "akey": "xval"]
    let sortedKeys = sortCaseInsensitive(Array(dict.keys))
0
Sebastian