it-swarm.com.de

Wie sortiere ich ein NSMutableArray mit benutzerdefinierten Objekten?

Was ich tun möchte, scheint ziemlich einfach zu sein, aber ich kann im Web keine Antworten finden. Ich habe eine NSMutableArray Anzahl von Objekten und sagen wir, es handelt sich um 'Personen'-Objekte. Ich möchte das NSMutableArray nach Person.birthDate sortieren, bei dem es sich um ein NSDate handelt.

Ich denke, es hat etwas mit dieser Methode zu tun:

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

In Java würde ich mein Objekt Comparable implementieren lassen oder Collections.sort mit einem benutzerdefinierten Inline-Komparator verwenden ... wie um alles in der Welt machen Sie das in Objective-C?

1240
rustyshelf

Methode vergleichen

Entweder implementieren Sie eine Vergleichsmethode für Ihr Objekt:

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

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

NSSortDescriptor (besser)

oder meist noch besser:

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

Sie können problemlos nach mehreren Schlüsseln sortieren, indem Sie dem Array mehrere hinzufügen. Die Verwendung von benutzerdefinierten Vergleichsmethoden ist ebenfalls möglich. Schauen Sie sich die Dokumentation an .

Blöcke (glänzend!)

Seit Mac OS X 10.6 und iOS 4 besteht auch die Möglichkeit, mit einem Block zu sortieren:

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

Die -compare: und blockbasierten Methoden sind im Allgemeinen viel schneller als die Verwendung von NSSortDescriptor, da letztere auf KVC basieren. Der Hauptvorteil der NSSortDescriptor -Methode besteht darin, dass Sie Ihre Sortierreihenfolge mithilfe von Daten anstelle von Code definieren können, wodurch es einfach wird, z. Richten Sie die Dinge so ein, dass Benutzer ein NSTableView sortieren können, indem Sie auf die Kopfzeile klicken.

2278
Georg Schölly

Siehe die NSMutableArray -Methode sortUsingFunction:context:

Sie müssen eine Vergleichsfunktion einrichten, die zwei Objekte (vom Typ Person) akzeptiert, da Sie zwei Person vergleichen. Objekte) und ein Kontext Parameter.

Die beiden Objekte sind nur Instanzen von Person. Das dritte Objekt ist eine Zeichenkette, z.B. @"Geburtsdatum".

Diese Funktion gibt ein NSComparisonResult zurück: Sie gibt NSOrderedAscending zurück, wenn _PersonA.birthDate_ <_PersonB.birthDate_. Es wird NSOrderedDescending zurückgegeben, wenn _PersonA.birthDate_> _PersonB.birthDate_. Schließlich wird NSOrderedSame zurückgegeben, wenn _PersonA.birthDate_ == _PersonB.birthDate_.

Dies ist ein grober Pseudocode. Sie müssen herausfinden, was es bedeutet, wenn ein Datum "weniger", "mehr" oder "gleich" mit einem anderen Datum ist (z. B. Vergleich von Sekunden seit der Epoche usw.):

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

Wenn Sie etwas kompakteres wollen, können Sie ternäre Operatoren verwenden:

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

Inlining könnte dies vielleicht etwas beschleunigen, wenn Sie dies häufig tun.

107
Alex Reynolds

Ich habe dies in iOS 4 mit einem Block gemacht. Musste die Elemente meines Arrays von id in meinen Klassentyp umwandeln. In diesem Fall war es eine Klasse namens Score mit einer Eigenschaft namens points.

Außerdem müssen Sie entscheiden, was zu tun ist, wenn die Elemente Ihres Arrays nicht den richtigen Typ haben. In diesem Beispiel habe ich NSOrderedSame zurückgegeben, in meinem Code habe ich jedoch eine Ausnahme gemacht.

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: Dies wird in absteigender Reihenfolge sortiert.

61
Chris

Ab iOS 4 können Sie Blöcke auch zum Sortieren verwenden.

In diesem Beispiel gehe ich davon aus, dass die Objekte in Ihrem Array eine 'position'-Methode haben, die ein NSInteger zurückgibt.

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

Hinweis: Das "sortierte" Array wird automatisch freigegeben.

28
leviathan

Ich habe alles versucht, aber das hat bei mir funktioniert. In einer Klasse habe ich eine andere Klasse mit dem Namen "crimeScene" und möchte nach einer Eigenschaft von "crimeScene" sortieren.

Das funktioniert wie ein Zauber:

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

Es fehlt ein Schritt in Georg Schöllys zweite Antwort , aber es funktioniert dann gut.

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

Danke, es funktioniert gut ...

18
Hardik Darji

Ihre Person Objekte müssen eine Methode implementieren, z. B. compare:, die ein anderes Person Objekt annimmt, und NSComparisonResult gemäß der Beziehung zwischen den beiden Objekten zurückgeben.

Dann würden Sie sortedArrayUsingSelector: mit @selector(compare:) aufrufen und es sollte getan werden.

Es gibt andere Möglichkeiten, aber meines Wissens gibt es kein Cocoa-Equiv der Comparable -Oberfläche. Die Verwendung von sortedArrayUsingSelector: ist wahrscheinlich der schmerzloseste Weg, dies zu tun.

16
freespace

iOS 4 Blöcke werden dich retten :)

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 ein bisschen Beschreibung

Verwenden Sie für NSMutableArray die Methode sortUsingSelector. Es sortiert die Position, ohne eine neue Instanz zu erstellen.

7
DenTheMan

Sie können die folgende generische Methode für Ihren Zweck verwenden. Es sollte Ihr Problem lösen.

//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
MD Aslam Ansari

Wenn Sie nur ein Array von NSNumbers sortieren, können Sie diese mit einem Aufruf sortieren:

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

Das funktioniert, weil die Objekte im Array (NSNumber Objekte) die Vergleichsmethode implementieren. Sie können dasselbe für NSString -Objekte oder sogar für ein Array von benutzerdefinierten Datenobjekten tun, die eine Vergleichsmethode implementieren.

Hier ist ein Beispielcode mit Komparatorblöcken. Es sortiert eine Reihe von Wörterbüchern, wobei jedes Wörterbuch eine Nummer in einem Schlüssel "sort_key" enthält.

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

Der obige Code durchläuft die Arbeit, einen ganzzahligen Wert für jeden Sortierschlüssel zu ermitteln und zu vergleichen, um zu veranschaulichen, wie dies getan wird. Da NSNumber -Objekte eine Vergleichsmethode implementieren, kann diese viel einfacher umgeschrieben werden:

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

oder der Körper des Komparators könnte sogar auf 1 Zeile herunterdestilliert werden:

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

Ich bevorzuge einfache Anweisungen und viele temporäre Variablen, da der Code leichter zu lesen und leichter zu debuggen ist. Der Compiler optimiert die temporären Variablen ohnehin weg, sodass die All-in-One-Line-Version keinen Vorteil bietet.

5
Dinesh_

Ich habe sortUsingFunction :: in einigen meiner Projekte verwendet:

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
roocell

Ich habe eine kleine Bibliothek von Kategoriemethoden mit dem Namen Linq to ObjectiveC erstellt, die dies einfacher macht. Mit der sort -Methode mit einer Schlüsselauswahl können Sie nach birthDate wie folgt sortieren:

NSArray* sortedByBirthDate = [input sort:^id(id person) {
    return [person birthDate];
}]
4
ColinE

Ich habe gerade eine mehrstufige Sortierung basierend auf benutzerdefinierten Anforderungen durchgeführt.

// sortiere die Werte

    [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
Boobalan
-(NSMutableArray*) sortArray:(NSMutableArray *)toBeSorted 
{
  NSArray *sortedArray;
  sortedArray = [toBeSorted sortedArrayUsingComparator:^NSComparisonResult(id a, id b) 
  {
    return [a compare:b];
 }];
 return [sortedArray mutableCopy];
}
3
Emile Khattar

Mit NSSortDescriptor können Sie ein NSMutableArray nach benutzerdefinierten Objekten sortieren

 NSSortDescriptor *sortingDescriptor;
 sortingDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
                                       ascending:YES];
 NSArray *sortArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]];
3
Arvind Patel

Das Sortieren von NSMutableArray ist sehr einfach:

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
Mohit

Mit den Protokollen und der funktionalen Programmierung von Swift ist es sehr einfach, Ihre Klasse an das Comparable-Protokoll anzupassen, die für das Protokoll erforderlichen Methoden zu implementieren und dann mithilfe der sortierten (nach:) Funktion höherer Ordnung ein sortiertes Array zu erstellen, ohne es verwenden zu müssen veränderbare Arrays übrigens.

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: {$0 > $1})

//print sasha which is p1
print(persons.first?.name)
//print James which is the "older"
print(sortedPersons.first?.name)
1
James Rochabrun

Mit NSComparator sortieren

Wenn wir benutzerdefinierte Objekte sortieren möchten, müssen wir NSComparator bereitstellen, mit dem benutzerdefinierte Objekte verglichen werden. Der Block gibt einen NSComparisonResult -Wert zurück, um die Reihenfolge der beiden Objekte anzugeben. Um also das gesamte Array zu sortieren, wird NSComparator folgendermaßen verwendet.

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

Sortiert mit NSSortDescriptor
Angenommen, wir haben ein Array mit Instanzen einer benutzerdefinierten Klasse. Employee hat die Attribute Vorname, Nachname und Alter. Das folgende Beispiel zeigt, wie ein NSSortDescriptor erstellt wird, mit dem der Array-Inhalt in aufsteigender Reihenfolge nach dem Altersschlüssel sortiert werden kann.

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

Mit benutzerdefinierten Vergleichen sortieren
Namen sind Zeichenfolgen. Wenn Sie Zeichenfolgen sortieren, die dem Benutzer angezeigt werden sollen, sollten Sie immer einen lokalisierten Vergleich verwenden. Oft möchten Sie auch einen Vergleich durchführen, bei dem die Groß- und Kleinschreibung nicht berücksichtigt wird. Hier kommt ein Beispiel mit (localizedStandardCompare :), um das Array nach Nachname und Vorname zu ordnen.

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

Referenz und ausführliche Informationen finden Sie unter: 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
Aamir

In meinem Fall verwende ich sortArrayUsingComparator, um ein Array zu sortieren. Schauen Sie sich den folgenden Code an.

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

Auch mein Objekt ist,

@interface ContactListData : JsonData
@property(nonatomic,strong) NSString * contactName;
@property(nonatomic,strong) NSString * contactSurname;
@property(nonatomic,strong) NSString * contactPhoneNumber;
@property(nonatomic) BOOL isSelected;
@end
0
Emre Gürses

Verwenden Sie wie folgt für verschachtelte Objekte,

NSSortDescriptor * sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastRoute.to.lastname" ascending:YES selector:@selector(caseInsensitiveCompare:)];
NSMutableArray *sortedPackages = [[NSMutableArray alloc]initWithArray:[packages sortedArrayUsingDescriptors:@[sortDescriptor]]];

lastRoute ist ein Objekt und dieses Objekt enthält das Objekt to, das Objekt to enthält die Zeichenfolgenwerte lastname.

Array in Swift sortieren


Für Swifty Person unten ist eine sehr saubere Technik, um das übergeordnete Ziel für global zu erreichen. Nehmen wir eine benutzerdefinierte Beispielklasse von User mit einigen Attributen.

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

Jetzt haben wir ein Array, das wir auf der Basis von createdDate entweder aufsteigend und/oder absteigend sortieren müssen. Fügen wir also eine Funktion für den Datumsvergleich hinzu.

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

Jetzt haben wir eine extension von Array für User. In einfachen Worten lassen Sie uns einige Methoden nur für diejenigen Arrays hinzufügen, die nur User Objekte enthalten.

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

Verwendung für aufsteigende Reihenfolge

let sortedArray = someArray.sortUserByDate(.orderedAscending)

Verwendung für absteigende Reihenfolge

let sortedArray = someArray.sortUserByDate(.orderedAscending)

Verwendung für die gleiche Bestellung

let sortedArray = someArray.sortUserByDate(.orderedSame)

Auf die obige Methode in extension kann nur zugegriffen werden, wenn Array vom Typ [User] || ist Array<User>

0

Sie müssen sortDescriptor erstellen und dann können Sie das nsmutablearray mit sortDescriptor wie folgt sortieren.

 let sortDescriptor = NSSortDescriptor(key: "birthDate", ascending: true, selector: #selector(NSString.compare(_:)))
 let array = NSMutableArray(array: self.aryExist.sortedArray(using: [sortDescriptor]))
 print(array)
0
Parth Barot