1321 votes

Comment trier un NSMutableArray avec des objets personnalisés?

Ce que je veux faire me semble assez simple, mais je ne trouve pas de réponses sur le web. J'ai un NSMutableArray d'objets, disons qu'elles sont 'Personne' objets. Je veux l' NSMutableArray par Personne.date de naissance qui est un NSDate.

Je pense qu'il a quelque chose à faire avec cette méthode:

NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(???)];

En Java, je voudrais faire mon objet de mettre en œuvre Comparable, ou de l'utilisation des Collections.tri avec une ligne personnalisé comparateur de...comment sur terre ne vous faites cela en Objective-C?

2345voto

Georg Schölly Points 63123

La méthode de comparaison

Soit vous mettez en œuvre une comparaison de la méthode de votre objet:

- (NSComparisonResult)compare:(Person *)otherObject {
    return [self.birthDate compare:otherObject.birthDate];
}

NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(compare:)];

NSSortDescriptor (mieux)

ou encore mieux:

NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
                                              ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingDescriptors:sortDescriptors];

Vous pouvez facilement trier par plusieurs clés en ajoutant plus d'une à la matrice. À l'aide personnalisée au comparateur de méthodes est possible. Jetez un oeil à la documentation.

Blocs (brillant!)

Il y a également la possibilité de trier avec un bloc de depuis Mac OS X 10.6 et iOS 4:

NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
    NSDate *first = [(Person*)a birthDate];
    NSDate *second = [(Person*)b birthDate];
    return [first compare:second];
}];

113voto

Alex Reynolds Points 45039

Voir l' NSMutableArray méthode sortUsingFunction:context:

Vous aurez besoin de mettre en place un comparez fonction qui prend deux objets (de type Person, car de la comparaison de deux Person des objets) et un contexte de paramètre.

Les deux objets sont juste des instances de Person. Le troisième objet est une chaîne de caractères, par exemple @"date de naissance".

Cette fonction retourne un NSComparisonResult: Elle retourne NSOrderedAscending si PersonA.birthDate < PersonB.birthDate. Il sera de retour NSOrderedDescending si PersonA.birthDate > PersonB.birthDate. Enfin, il sera de retour NSOrderedSame si PersonA.birthDate == PersonB.birthDate.

C'est rugueux pseudo-code, vous aurez besoin de chair sur ce que signifie, pour une date à être "moins", "plus" ou "égalité" à une autre date:

NSComparisonResult compare(Person *firstPerson, Person *secondPerson, void *context) {
  if ([firstPerson birthDate] < [secondPerson birthDate])
    return NSOrderedAscending;
  else if ([firstPerson birthDate] > [secondPerson birthDate])
    return NSOrderedDescending;
  else 
    return NSOrderedSame;
}

66voto

Chris Points 566

Je l'ai fait en iOS 4 à l'aide d'un bloc. Devait jeter les éléments de mon tableau à partir de l'id de mon type de classe. Dans ce cas, c'était une classe appelée Score avec une propriété appelée points.

Aussi, vous devez décider quoi faire si les éléments de votre tableau ne sont pas du bon type, pour cet exemple, je viens de rentrer NSOrderedSame, mais dans mon code j'ai bien une exception.

NSArray *sorted = [_scores sortedArrayUsingComparator:^(id obj1, id obj2){
    if ([obj1 isKindOfClass:[Score class]] && [obj2 isKindOfClass:[Score class]]) {
        Score *s1 = obj1;
        Score *s2 = obj2;

        if (s1.points > s2.points) {
            return (NSComparisonResult)NSOrderedAscending;
        } else if (s1.points < s2.points) {
            return (NSComparisonResult)NSOrderedDescending;
        }
    }

    // TODO: default is the same?
    return (NSComparisonResult)NSOrderedSame;
}];

return sorted;

PS: C'est un tri dans l'ordre décroissant.

31voto

Fernando Redondo Points 530

J'ai tout essayé, mais cela a fonctionné pour moi. Dans une classe, j'ai une autre classe nommée "crimeScene", et souhaitez effectuer un tri par la propriété de "crimeScene".

Cela fonctionne comme un charme!

NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:@"crimeScene.distance" ascending:YES];
[self.arrAnnotations sortUsingDescriptors:[NSArray arrayWithObject:sorter]];

30voto

leviathan Points 5207

Départ en iOS 4 vous pouvez également utiliser des blocs pour le tri.

Pour cet exemple particulier, je suis en supposant que les objets dans votre tableau ont une "position" de la méthode, qui renvoie un NSInteger.

NSArray *arrayToSort = where ever you get the array from... ;
NSComparisonResult (^sortBlock)(id, id) = ^(id obj1, id obj2) {
  if ([obj1 position] > [obj2 position]) { 
    return (NSComparisonResult)NSOrderedDescending;
  }
  if ([obj1 position] < [obj2 position]) {
    return (NSComparisonResult)NSOrderedAscending;
  }
  return (NSComparisonResult)NSOrderedSame;
};
NSArray *sorted = [arrayToSort sortedArrayUsingComparator:sortBlock];

Remarque: le "triés" tableau sera autoreleased.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X