Comment puis-je trier un Nsmutablarray avec des objets personnalisés?

ce que je veux faire semble assez simple, mais je ne trouve pas de réponses sur le web. J'ai un NSMutableArray d'objets, et disons que ce sont des objets "de personne". Je veux trier le NSMutableArray par personne.date de naissance qui est un NSDate .

je pense que cela a quelque chose à voir avec cette méthode:

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

en Java je rendrais mon objet implémenter Comparable, ou utiliser des Collections.trier avec un comparateur personnalisé en ligne...comment sur la terre ne vous faites ça dans L'objectif-C?

1185
demandé sur Peter Mortensen 2009-04-30 10:10:56
la source

25 ответов

méthode de comparaison

soit vous implémentez une méthode de comparaison pour votre objet:

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

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

NSSortDescriptor (better)

ou Habituellement même mieux:

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

vous pouvez facilement Trier par plusieurs touches en ajoutant plus d'une au tableau. Utiliser des méthodes de comparaison personnalisées est également possible. Jetez un oeil à la documentation .

blocs (brillant!)

Il ya aussi la possibilité de tri avec un bloc 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];
}];

Performance

les méthodes -compare: et basées sur des blocs seront un peu plus rapides, en général, que l'utilisation de NSSortDescriptor car cette dernière s'appuie sur KVC. Le principal avantage de la méthode NSSortDescriptor est qu'elle fournit une façon de définir votre ordre de tri en utilisant des données, plutôt que le code, ce qui rend facile à par exemple, configurez les choses pour que les utilisateurs puissent Trier un NSTableView en cliquant sur la ligne d'en-tête.

2226
répondu Georg Schölly 2017-06-12 17:50:16
la source

voir la méthode NSMutableArray sortUsingFunction:context:

vous aurez besoin de configurer une fonction comparer qui prend deux objets (de type Person , puisque vous comparez deux Person objets) et un contexte paramètre.

les deux objets ne sont que des instances de Person . Le troisième objet est une chaîne de caractères, par exemple @"birthDate".

Cette fonction renvoie un NSComparisonResult : elle renvoie NSOrderedAscending si PersonA.birthDate < PersonB.birthDate . Il retournera NSOrderedDescending si PersonA.birthDate > PersonB.birthDate . Enfin, il retournera NSOrderedSame si PersonA.birthDate = = PersonB.birthDate .

c'est un pseudo rugueux; vous aurez besoin de préciser ce que cela signifie pour une date pour être" moins"," plus "ou" égal " à une autre date (comme comparer secondes-depuis-époque, etc.):

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;
}

si vous voulez quelque chose de plus compact, vous pouvez utiliser des opérateurs ternaires:

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

Inline pourrait peut-être accélérer un peu, si vous faites cela, beaucoup.

103
répondu Alex Reynolds 2016-06-13 20:21:52
la source

j'ai fait ça dans iOS 4 en utilisant un bloc. J'ai du lancer les éléments de mon tableau de id à mon type de classe. Dans ce cas, c'était une classe appelée Score avec une propriété appelée points.

vous devez aussi décider ce qu'il faut faire si les éléments de votre tableau ne sont pas le bon type, pour cet exemple je viens de retourner NSOrderedSame , cependant dans mon code j'ai fait 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: Tri par ordre décroissant.

58
répondu Chris 2013-06-03 11:22:00
la source

à partir de iOS 4, Vous pouvez également utiliser des blocs pour le tri.

pour cet exemple particulier, je suppose que les objets dans votre tableau ont une méthode de" position", 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];

Note: le tableau" trié " sera auto-libéré.

28
répondu leviathan 2016-06-13 12:52:16
la source

j'ai tout essayé, mais ça a marché 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]];
24
répondu Fernando Redondo 2016-12-24 10:40:28
la source

il manque une étape dans la deuxième réponse DE Georg Schölly , mais cela fonctionne très bien alors.

NSSortDescriptor *sortDescriptor;
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate"
                                              ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingDescriptor:sortDescriptors];
19
répondu Manuel Spuhler 2017-05-23 15:34:39
la source
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate" ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingDescriptors:sortDescriptors];

merci, ça marche très bien...

18
répondu Hardik Darji 2016-01-31 21:00:00
la source

votre Person objets doivent mettre en œuvre une méthode, dire compare: qui prend un autre Person objet, et retourner NSComparisonResult selon la relation entre les 2 objets.

alors vous appelleriez sortedArrayUsingSelector: avec @selector(compare:) et cela devrait être fait.

il y a d'autres moyens, mais pour autant que je sache il n'y a pas de Cocoa-equiv de l'interface Comparable . Utiliser sortedArrayUsingSelector: est probablement la manière la plus indolore de faire il.

16
répondu freespace 2009-04-30 10:25:14
la source

iOS 4 pâtés de maisons, vous fera économiser :)

featuresArray = [[unsortedFeaturesArray sortedArrayUsingComparator: ^(id a, id b)  
{
    DMSeatFeature *first = ( DMSeatFeature* ) a;
    DMSeatFeature *second = ( DMSeatFeature* ) b;

    if ( first.quality == second.quality )
        return NSOrderedSame;
    else
    {
        if ( eSeatQualityGreen  == m_seatQuality || eSeatQualityYellowGreen == m_seatQuality || eSeatQualityDefault  == m_seatQuality )
        {
            if ( first.quality < second.quality )
                return NSOrderedAscending;
            else
                return NSOrderedDescending;
        }
        else // eSeatQualityRed || eSeatQualityYellow
        {
            if ( first.quality > second.quality )
                return NSOrderedAscending;
            else
                return NSOrderedDescending;
        } 
    }
}] retain];

http://sokol8.blogspot.com/2011/04/sorting-nsarray-with-blocks.html un peu de description

8
répondu Kostiantyn Sokolinskyi 2016-08-08 15:21:10
la source

pour NSMutableArray , utilisez la méthode sortUsingSelector . Il trie it-place, sans créer une nouvelle instance.

7
répondu DenTheMan 2013-06-03 11:23:14
la source

Vous pouvez utiliser la méthode générique pour votre but. Cela devrait résoudre votre problème.

//Called method
-(NSMutableArray*)sortArrayList:(NSMutableArray*)arrDeviceList filterKeyName:(NSString*)sortKeyName ascending:(BOOL)isAscending{
    NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:sortKeyName ascending:isAscending];
    [arrDeviceList sortUsingDescriptors:[NSArray arrayWithObject:sorter]];
    return arrDeviceList;
}

//Calling method
[self sortArrayList:arrSomeList filterKeyName:@"anything like date,name etc" ascending:YES];
6
répondu MD Aslam Ansari 2015-09-29 23:56:35
la source

si vous êtes juste en train de trier un tableau de NSNumbers , vous pouvez les trier avec 1 appel:

[arrayToSort sortUsingSelector: @selector(compare:)];

qui fonctionne parce que les objets du tableau ( NSNumber objets) implémentent la méthode de comparaison. Vous pouvez faire la même chose pour les objets NSString , ou même pour un tableau d'objets de données personnalisés qui implémentent une méthode de comparaison.

voici un exemple de code utilisant des blocs de comparaison. Il trie un tableau de dictionnaires où chaque dictionnaire comprend un nombre dans une clé "sort_key".

#define SORT_KEY @\"sort_key\"

[anArray sortUsingComparator: 
 ^(id obj1, id obj2) 
  {
  NSInteger value1 = [[obj1 objectForKey: SORT_KEY] intValue];
  NSInteger value2 = [[obj2 objectForKey: SORT_KEY] intValue];
  if (value1 > value2) 
{
  return (NSComparisonResult)NSOrderedDescending;
  }

  if (value1 < value2) 
{
  return (NSComparisonResult)NSOrderedAscending;
  }
    return (NSComparisonResult)NSOrderedSame;
 }];

le code ci-dessus passe par le travail d'obtenir une valeur entière pour chaque clé de tri et de les comparer, comme une illustration de la façon de le faire. Puisque les objets NSNumber implémentent une méthode de comparaison, elle pourrait être réécrite beaucoup plus simplement:

 #define SORT_KEY @\"sort_key\"

[anArray sortUsingComparator: 
^(id obj1, id obj2) 
 {
  NSNumber* key1 = [obj1 objectForKey: SORT_KEY];
  NSNumber* key2 = [obj2 objectForKey: SORT_KEY];
  return [key1 compare: key2];
 }];

ou le corps du comparateur pourrait même être distillé jusqu'à 1 ligne:

  return [[obj1 objectForKey: SORT_KEY] compare: [obj2 objectForKey: SORT_KEY]];

j'ai tendance à préférer les déclarations simples et beaucoup de variables temporaires car le code est plus facile à lire et plus facile à déboguer. Le compilateur optimise de toute façon les variables temporaires, de sorte qu'il n'y a aucun avantage à la version tout-en-une-ligne.

5
répondu Dinesh_ 2013-06-03 11:22:57
la source

j'ai créé une petite bibliothèque de méthodes de catégorie, appelé Linq à ObjectiveC , qui rend ce genre de chose plus facile. En utilisant la méthode trier avec un sélecteur de clé, vous pouvez trier par birthDate comme suit:

NSArray* sortedByBirthDate = [input sort:^id(id person) {
    return [person birthDate];
}]
4
répondu ColinE 2013-03-06 12:29:13
la source

je viens de faire le tri multi-niveaux basé sur des exigences personnalisées.

//trier les valeurs

    [arrItem sortUsingComparator:^NSComparisonResult (id a, id b){

    ItemDetail * itemA = (ItemDetail*)a;
    ItemDetail* itemB =(ItemDetail*)b;

    //item price are same
    if (itemA.m_price.m_selling== itemB.m_price.m_selling) {

        NSComparisonResult result=  [itemA.m_itemName compare:itemB.m_itemName];

        //if item names are same, then monogramminginfo has to come before the non monograme item
        if (result==NSOrderedSame) {

            if (itemA.m_monogrammingInfo) {
                return NSOrderedAscending;
            }else{
                return NSOrderedDescending;
            }
        }
        return result;
    }

    //asscending order
    return itemA.m_price.m_selling > itemB.m_price.m_selling;
}];

https://sites.google.com/site/greateindiaclub/mobil-apps/ios/multilevelsortinginiosobjectivec

4
répondu Boobalan 2014-12-13 06:06:46
la source

j'ai utilisé sortUsingFunction:: dans certains de mes projets:

int SortPlays(id a, id b, void* context)
{
    Play* p1 = a;
    Play* p2 = b;
    if (p1.score<p2.score) 
        return NSOrderedDescending;
    else if (p1.score>p2.score) 
        return NSOrderedAscending;
    return NSOrderedSame;
}

...
[validPlays sortUsingFunction:SortPlays context:nil];
4
répondu roocell 2016-01-31 21:00:53
la source
-(NSMutableArray*) sortArray:(NSMutableArray *)toBeSorted 
{
  NSArray *sortedArray;
  sortedArray = [toBeSorted sortedArrayUsingComparator:^NSComparisonResult(id a, id b) 
  {
    return [a compare:b];
 }];
 return [sortedArray mutableCopy];
}
3
répondu Emile Khattar 2013-01-11 15:32:29
la source

Tri NSMutableArray est très simple:

NSMutableArray *arrayToFilter =
     [[NSMutableArray arrayWithObjects:@"Photoshop",
                                       @"Flex",
                                       @"AIR",
                                       @"Flash",
                                       @"Acrobat", nil] autorelease];

NSMutableArray *productsToRemove = [[NSMutableArray array] autorelease];

for (NSString *products in arrayToFilter) {
    if (fliterText &&
        [products rangeOfString:fliterText
                        options:NSLiteralSearch|NSCaseInsensitiveSearch].length == 0)

        [productsToRemove addObject:products];
}
[arrayToFilter removeObjectsInArray:productsToRemove];
2
répondu Mohit 2016-01-31 21:02:06
la source

trier en utilisant le comparateur NS

si nous voulons trier des objets personnalisés , nous devons fournir NSComparator , qui est utilisé pour comparer des objets personnalisés. Le bloc renvoie une valeur NSComparisonResult pour indiquer l'ordre des deux objets. Afin de trier tout le tableau NSComparator est utilisé de la manière suivante.

NSArray *sortedArray = [employeesArray sortedArrayUsingComparator:^NSComparisonResult(Employee *e1, Employee *e2){
    return [e1.firstname compare:e2.firstname];    
}];

Tries Using NSSortDescriptor

Supposons, par exemple, que nous avons un tableau contenant des instances d'une classe personnalisée, Employee a les attributs firstname, lastname et age. L'exemple suivant illustre comment créer un Nssortdescripteur qui peut être utilisé pour trier le contenu du tableau dans l'ordre croissant par la touche age.

NSSortDescriptor *ageDescriptor = [[NSSortDescriptor alloc] initWithKey:@"age" ascending:YES];
NSArray *sortDescriptors = @[ageDescriptor];
NSArray *sortedArray = [employeesArray sortedArrayUsingDescriptors:sortDescriptors];

trier en utilisant des comparaisons personnalisées

Les noms sont des chaînes, et lorsque vous triez des chaînes pour les présenter à l'utilisateur, vous devriez toujours utiliser un localisée comparaison. Souvent, vous voulez également effectuer une comparaison non sensible à la casse. Voici un exemple avec (localizedstandcompare:) pour ordonner le tableau par nom et prénom.

NSSortDescriptor *lastNameDescriptor = [[NSSortDescriptor alloc]
              initWithKey:@"lastName" ascending:YES selector:@selector(localizedStandardCompare:)];
NSSortDescriptor * firstNameDescriptor = [[NSSortDescriptor alloc]
              initWithKey:@"firstName" ascending:YES selector:@selector(localizedStandardCompare:)];
NSArray *sortDescriptors = @[lastNameDescriptor, firstNameDescriptor];
NSArray *sortedArray = [employeesArray sortedArrayUsingDescriptors:sortDescriptors];

Pour la référence et la discussion détaillée, veuillez vous référer: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/SortDescriptors/Articles/Creating.html

http://www.ios-blog.co.uk/tutorials/objective-c/how-to-sort-nsarray-with-custom-objects /

1
répondu Aamir 2016-06-17 08:12:49
la source

les protocoles et la programmation fonctionnelle de Swift rendent cela très facile il vous suffit de rendre votre classe conforme au protocole Comparable, mettre en œuvre les méthodes requises par le protocole et ensuite utiliser la fonction triée(par: ) d'ordre élevé pour créer un tableau trié sans avoir besoin d'utiliser des tableaux mutables d'ailleurs.

class Person: Comparable {
    var birthDate: NSDate?
    let name: String

    init(name: String) {
        self.name = name
    }

    static func ==(lhs: Person, rhs: Person) -> Bool {
        return lhs.birthDate === rhs.birthDate || lhs.birthDate?.compare(rhs.birthDate as! Date) == .orderedSame
    }

    static func <(lhs: Person, rhs: Person) -> Bool {
        return lhs.birthDate?.compare(rhs.birthDate as! Date) == .orderedAscending
    }

    static func >(lhs: Person, rhs: Person) -> Bool {
        return lhs.birthDate?.compare(rhs.birthDate as! Date) == .orderedDescending
    }

}

let p1 = Person(name: "Sasha")
p1.birthDate = NSDate() 

let p2 = Person(name: "James")
p2.birthDate = NSDate()//he is older by miliseconds

if p1 == p2 {
    print("they are the same") //they are not
}

let persons = [p1, p2]

//sort the array based on who is older
let sortedPersons = persons.sorted(by: {"151900920" > })

//print sasha which is p1
print(persons.first?.name)
//print James which is the "older"
print(sortedPersons.first?.name)
1
répondu James Rochabrun 2017-03-28 01:14:35
la source

dans mon cas, j'utilise" sortedArrayUsingComparator " pour trier un tableau. Regardez le code ci-dessous.

contactArray = [[NSArray arrayWithArray:[contactSet allObjects]] sortedArrayUsingComparator:^NSComparisonResult(ContactListData *obj1, ContactListData *obj2) {
    NSString *obj1Str = [NSString stringWithFormat:@"%@ %@",obj1.contactName,obj1.contactSurname];
    NSString *obj2Str = [NSString stringWithFormat:@"%@ %@",obj2.contactName,obj2.contactSurname];
    return [obj1Str compare:obj2Str];
}];

aussi mon objet est,

@interface ContactListData : JsonData
@property(nonatomic,strong) NSString * contactName;
@property(nonatomic,strong) NSString * contactSurname;
@property(nonatomic,strong) NSString * contactPhoneNumber;
@property(nonatomic) BOOL isSelected;
@end
0
répondu Emre Gürses 2017-11-28 17:00:21
la source

Tableau De Tri Dans Swift


Pour Swifty Personne ci-dessous est très propre technique pour atteindre l'objectif ci-dessus à l'échelle mondiale. Permet d'avoir un exemple de classe personnalisée de User qui ont certains attributs.

class User: NSObject {
    var id: String?
    var name: String?
    var email: String?
    var createdDate: Date?
}

maintenant nous avons un tableau que nous devons trier sur la base de createdDate soit ascendant et/ou descendant. Donc, permet d'ajouter une fonction pour la comparaison de date.

class User: NSObject {
    var id: String?
    var name: String?
    var email: String?
    var createdDate: Date?
    func checkForOrder(_ otherUser: User, _ order: ComparisonResult) -> Bool {
        if let myCreatedDate = self.createdDate, let othersCreatedDate = otherUser.createdDate {
            //This line will compare both date with the order that has been passed.
            return myCreatedDate.compare(othersCreatedDate) == order
        }
        return false
    }
}

permet maintenant d'avoir un extension de Array pour User . En termes simples, permet d'ajouter quelques méthodes uniquement pour les tableaux qui n'ont que des objets User .

extension Array where Element: User {
    //This method only takes an order type. i.e ComparisonResult.orderedAscending
    func sortUserByDate(_ order: ComparisonResult) -> [User] {
        let sortedArray = self.sorted { (user1, user2) -> Bool in
            return user1.checkForOrder(user2, order)
        }
        return sortedArray
    }
}

l'Utilisation par Ordre Croissant

let sortedArray = someArray.sortUserByDate(.orderedAscending)

utilisation pour L'ordre descendant

let sortedArray = someArray.sortUserByDate(.orderedAscending)

Utilisation pour la même commande

let sortedArray = someArray.sortUserByDate(.orderedSame)

ci-dessus dans extension ne sera accessible que si le Array est de type [User] || Array<User>

0
répondu Syed Qamar Abbas 2018-03-25 00:20:34
la source

vous devez créer sortDescriptor et ensuite vous pouvez trier le nsmutablarray en utilisant sortDescriptor comme ci-dessous.

 let sortDescriptor = NSSortDescriptor(key: "birthDate", ascending: true, selector: #selector(NSString.compare(_:)))
 let array = NSMutableArray(array: self.aryExist.sortedArray(using: [sortDescriptor]))
 print(array)
0
répondu Parth Barot 2018-04-12 13:32:49
la source

vous utilisez NSSortDescriptor pour trier un NSMutableArray avec des objets personnalisés

 NSSortDescriptor *sortingDescriptor;
 sortingDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
                                       ascending:YES];
 NSArray *sortArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]];
0
répondu Arvind Patel 2018-06-14 12:21:27
la source
NSSortDescriptor  *sort = [[NSSortDescriptor alloc] initWithKey:@"_strPrice"
                                                 ascending:sortFlag selector:@selector(localizedStandardCompare:)] ;
-1
répondu 2015-01-05 10:00:45
la source
NSMutableArray *stockHoldingCompanies = [NSMutableArray arrayWithObjects:fortune1stock,fortune2stock,fortune3stock,fortune4stock,fortune5stock,fortune6stock , nil];

NSSortDescriptor *sortOrder = [NSSortDescriptor sortDescriptorWithKey:@"companyName" ascending:NO];

[stockHoldingCompanies sortUsingDescriptors:[NSArray arrayWithObject:sortOrder]];

NSEnumerator *enumerator = [stockHoldingCompanies objectEnumerator];

ForeignStockHolding *stockHoldingCompany;

NSLog(@"Fortune 6 companies sorted by Company Name");

    while (stockHoldingCompany = [enumerator nextObject]) {
        NSLog(@"===============================");
        NSLog(@"CompanyName:%@",stockHoldingCompany.companyName);
        NSLog(@"Purchase Share Price:%.2f",stockHoldingCompany.purchaseSharePrice);
        NSLog(@"Current Share Price: %.2f",stockHoldingCompany.currentSharePrice);
        NSLog(@"Number of Shares: %i",stockHoldingCompany.numberOfShares);
        NSLog(@"Cost in Dollars: %.2f",[stockHoldingCompany costInDollars]);
        NSLog(@"Value in Dollars : %.2f",[stockHoldingCompany valueInDollars]);
    }
    NSLog(@"===============================");
-3
répondu Siddhesh Bondre 2014-04-08 03:26:05
la source