web-dev-qa-db-fra.com

Trier NSArray avec triArrayUsingComparator

Dans Objective-C, je peux trier une NSArray en utilisant cette déclaration:

NSArray *sortedArray = [persons sortedArrayUsingComparator:^NSComparisonResult(Person *p1, Person *p2) {
    return [p1.name compare:p2.name];
}];

Je suis incapable de reproduire la même déclaration avec Swift . Tout ce que j'ai trouvé utilisait Array.

24
Paulo Rodrigues

Vous pouvez utiliser les fonctions de tri intégrées de Swift ou, puisqu'un tableau Swift est ponté sur NSArray, vous pouvez appeler sortedArrayUsingComparator directement depuis Swift.

Utilisation de la fonction sorted de Swift:

var sortedArray = sorted(persons) {
    (obj1, obj2) in

    // The downcast to Person is only needed if persons is an NSArray or a Swift Array of AnyObjects
    let p1 = obj1 as Person
    let p2 = obj2 as Person
    return p1.name < p2.name
}

Ou, en utilisant NSArray 's sortedArrayUsingComparator:

var sortedArray = persons.sortedArrayUsingComparator {
    (obj1, obj2) -> NSComparisonResult in

    let p1 = obj1 as Person
    let p2 = obj2 as Person
    let result = p1.name.compare(p2.name)
    return result
}
36
Mike S

Il n'y a pas besoin d'éviter Swift Array.

Il est ponté dans les deux sens avec NSArray. Par conséquent, pour un code plus sûr en termes de types, il est préférable de travailler avec les baies et le tableau Swift uniquement lorsque cela est nécessaire pour l'interopérabilité avec les API ObjC. (Et dans la plupart des API importées, Swift convertit automatiquement NSArray en [AnyObject], de sorte que vous n'avez même pas besoin de créer de passerelles très souvent.)

En supposant que le tableau persons soit un [AnyObject] que vous avez obtenu d'une autre API, vous pouvez réduire le nombre de transformations de types par rapport aux autres réponses en convertissant d'abord le tableau:

let sortedPersons = sorted(persons as [Person]) { $0.name < $1.name }
// sortedPersons has inferred type [Person]

De plus, comme vous utilisez un bloc de comparaison uniquement pour trier une propriété spécifique de votre classe Person, vous feriez peut-être mieux d'utiliser des descripteurs de tri:

let sortedPersons = (persons as NSArray).sortedArrayUsingDescriptors([
    NSSortDescriptor(key: "name", ascending: true)
])

(La partie persons as NSArray peut ne pas être nécessaire si persons provient d'une API ObjC.)

Selon la façon dont la classe Person est implémentée, le tri avec des descripteurs peut produire un tri plus efficace sur le backend. Par exemple, s'il s'agit d'un objet géré Core Data, le tri avec des descripteurs peut générer une requête SQL rapide dans la base de données et utilisant peu de mémoire, tandis que le tri avec une fermeture de comparateur nécessite l'instanciation de chaque objet à partir de la base de données, juste pour évaluer la fermeture par rapport à chaque objet. .

14
rickster

Essayez donc d'écrire la même chose avec Swift:

var sortedArray:NSArray = 
persons.sortedArrayUsingComparator(){(p1:AnyObject!, p2:AnyObject!) -> NSComparisonResult in

    if (p1 as Person).name > (p2 as Person).name {
       return NSComparisonResult.OrderedDescending
    }
    if (p1 as Person).name < (p2 as Person).name {
        return NSComparisonResult.OrderedAscending
    }
    return NSComparisonResult.OrderedAscending
 }

Test (Aire de jeu):

class Person{
  var name:String?
}

var p1:Person = Person()
p1.name = "a"    

var p3:Person = Person()
p3.name = "c"

var p2:Person = Person()
p2.name = "b"

var persons:NSArray = [p1,p3,p2]

var sortedArray:NSArray = persons.sortedArrayUsingComparator(){

    (p1:AnyObject!, p2:AnyObject!) -> NSComparisonResult in

    if (p1 as Person).name > (p2 as Person).name {
       return NSComparisonResult.OrderedDescending
    }
    if (p1 as Person).name < (p2 as Person).name {
        return NSComparisonResult.OrderedAscending
    }
    return NSComparisonResult.OrderedAscending
    }

for item:AnyObject in sortedArray{
    println((item as Person).name)
}

Sortie:

Optional("a")
Optional("b")
Optional("c")
9
Maxim Shoustin

Dans Swift, vous pouvez utiliser une nouvelle approche. Essayez d'utiliser la méthode triée à la place de sortArrayUsingComparator comme ceci ...

var sortedArray = results.sorted {
    (obj1, obj2) -> Bool in 
    return obj1.count! > obj2.count!
}
0
d0ping

au cas où vous avez un objet personnalisé et que vous souhaitez trier par date

let sortedArray = self.posts.sorted {
            (obj1, obj2) -> Bool in
            return (obj1 as! PostModel).orderCancellionDate.compare( (obj2 as! PostModel).orderCancellionDate) == .orderedDescending
        }
0
Spydy