ios - Comment trier un NSMutableArray avec des objets personnalisés?




objective-c sorting (17)

Comparer la méthode

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 (mieux)

ou habituellement encore mieux:

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

Vous pouvez facilement trier par plusieurs clés en ajoutant plus d'un au tableau. L'utilisation de méthodes de comparaison personnalisées est également possible. Jetez un oeil à la documentation .

Blocs (brillants!)

Il y a aussi la possibilité de trier 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 -compare: et block-based seront en général un peu plus rapides que l'utilisation de NSSortDescriptor car ce dernier repose sur KVC. Le principal avantage de la méthode NSSortDescriptor est qu'elle permet de définir votre ordre de tri à l'aide de données, plutôt que de code, ce qui facilite la configuration des éléments afin que les utilisateurs puissent trier un NSTableView en cliquant sur la ligne d'en-tête.

Ce que je veux faire semble assez simple, mais je ne trouve aucune réponse sur le web. J'ai un NSMutableArray d'objets, et disons qu'il s'agit d'objets 'Person'. Je veux trier NSMutableArray par Person.birthDate 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 comparable à Compare, ou utiliser Collections.sort avec un comparateur personnalisé en ligne ... comment diable faites-vous cela en Objective-C?


Trier le tableau dans Swift

Pour Swifty Person ci-dessous est une technique très propre à atteindre au-dessus du but pour globalement. Permet d'avoir un exemple de classe personnalisée d' User qui possède 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. Ajoutons donc 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
    }
}

Prenons maintenant une extension de Array for User . En termes simples, permet d'ajouter des méthodes uniquement pour les tableaux qui ne contiennent 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
    }
}

Utilisation pour l'ordre croissant

let sortedArray = someArray.sortUserByDate(.orderedAscending)

Utilisation pour l'ordre décroissant

let sortedArray = someArray.sortUserByDate(.orderedAscending)

Utilisation pour la même commande

let sortedArray = someArray.sortUserByDate(.orderedSame)

La méthode ci-dessus en extension ne sera accessible que si le Array est de type [User] || Array<User>


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

Il y a une étape manquante dans la deuxième réponse de Georg Schölly , mais cela fonctionne bien.

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

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

Ça fonctionne super bien:

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

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

Je viens de faire un tri à plusieurs niveaux en fonction des besoins personnalisés.

// 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


Le tri de 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];

Pour NSMutableArray , utilisez la méthode sortUsingSelector . Il trie le lieu, sans créer une nouvelle instance.


Si vous ne faites que trier un tableau de NSNumbers , vous pouvez les trier avec 1 appel:

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

Cela fonctionne parce que les objets dans le tableau (objets NSNumber ) 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 comparateurs. Il trie un tableau de dictionnaires où chaque dictionnaire inclut 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. Comme les objets NSNumber implémentent une méthode de comparaison, il est possible de la réécrire 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 instructions 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, donc il n'y a aucun avantage à la version tout-en-un-ligne.


Vos objets Person ont besoin d'implémenter une méthode, disons compare: qui prend un autre objet Person , et renvoient NSComparisonResult fonction de la relation entre les 2 objets.

Ensuite, vous appelez sortedArrayUsingSelector: avec @selector(compare:) et cela devrait être fait.

Il y a d'autres façons, mais pour autant que je sache, il n'y a pas d'équivalent Cocoa de l'interface Comparable . Utiliser sortedArrayUsingSelector: est probablement le moyen le plus simple de le faire.


Vous devez créer sortDescriptor et ensuite vous pouvez trier le nsmutablearray 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)

Vous pouvez utiliser la méthode générique suivante pour votre objectif. 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];

iOS 4 blocs vous sauvera :)

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


-(NSMutableArray*) sortArray:(NSMutableArray *)toBeSorted 
{
  NSArray *sortedArray;
  sortedArray = [toBeSorted sortedArrayUsingComparator:^NSComparisonResult(id a, id b) 
  {
    return [a compare:b];
 }];
 return [sortedArray mutableCopy];
}

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(@"===============================");

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

Merci, ça marche bien ...





nsmutablearray