Sortieren Sie NSArray nach Datumszeichenfolgen oder Objekten


86

Ich habe eine NSArray, die Datumszeichenfolgen (dh NSString) wie folgt enthält : "Do, 21. Mai 09 19:10:09 -0700"

Ich muss das NSArrayDatum sortieren . Ich dachte zuerst darüber nach, die Datumszeichenfolge in ein NSDateObjekt zu konvertieren , blieb aber dort hängen, wie man nach dem NSDateObjekt sortiert .

Vielen Dank.


Retagged, da dies mit dem Foundation-Framework zusammenhängt und nicht spezifisch für das iPhone ist.
Quinn Taylor

Antworten:


110

Speichern Sie die Daten als NSDateObjekte in einem NS-Array (veränderbar) und verwenden Sie dann -[NSArray sortedArrayUsingSelector:oder -[NSMutableArray sortUsingSelector:]und übergeben Sie sie @selector(compare:)als Parameter. Die -[NSDate compare:]Methode ordnet die Daten in aufsteigender Reihenfolge für Sie. Dies ist einfacher als das Erstellen einer NSSortDescriptorund viel einfacher als das Schreiben einer eigenen Vergleichsfunktion. ( NSDateObjekte wissen, wie sie sich mindestens so effizient miteinander vergleichen können, wie wir es uns mit benutzerdefiniertem Code erhoffen können.)


11
Es ist nicht klar, ob die ursprüngliche Frage das Sortieren eines Arrays von Datumsangaben oder das Sortieren eines Arrays von Objekten mit einem Datumsfeld betraf. Dies ist der einfachste Ansatz, wenn es der erstere ist, aber wenn es der letztere ist, ist NSSortDescriptor der richtige Weg.
Smorgan

@smorgan Wie geht NSSortDescriptor mit Null-Daten um?
Ash

Vielen Dank für Ihre Hilfe. Ich denke, wir sollten mehr in Apple Docs lesen, aber es scheint so langweilig, bis Sie es verwenden.
Abo3atef

1
Könnten Sie dies als Beispiel in einem Snippet-Code zeigen? Danke im Voraus.
uplearnedu.com

115

Wenn ich eines NSMutableArrayvon Objekten mit einem Feld "beginDate" vom Typ NSDatehabe, verwende ich eines NSSortDescriptorwie folgt :

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"beginDate" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];

3
Ich weiß, dass viel Zeit vergangen ist (als die vorherige Antwort akzeptiert wurde, konnte es noch keinen NSSortDescriptor geben), aber für die zukünftige Verwendung sollte dies die richtige Antwort sein.
Vive

1
Dies ist eine großartige Lösung. löste mein Problem in ein paar Zeilen Code.Thanx eine Tonne @vinzenzweber
Pratyusha Terli

1
Wirklich ... ich war wirklich schockiert, dass dies beim ersten Lauf funktioniert hat! Ich dachte, initWithKey sei für Wörterbücher reserviert, in denen der Schlüssel definiert ist, aber alles, was Sie tun müssen, ist auf eine Eigenschaft in einem Array von Objekten zu verweisen? Lass das Licht scheinen vinzenzweberskavitchski !!
Whyoz

NSSortDescriptor gibt es seit OS X 10.3 Ende 2003. Dies ist ein etwas anderes Szenario, bei dem das Datum ein Feld in einem anderen Objekt ist. Mit einer noch moderneren API können Sie auch -[NSMutableArray sortUsingComparator:](10.6+) verwenden und einen Block übergeben, der das Ergebnis des Aufrufs -compare:der beiden Felder zurückgibt . Es wäre wahrscheinlich schneller als -valueForKey:jedes Objekt aufzurufen . Sie können sogar -sortWithOptions:usingComparator:Optionen verwenden und übergeben, um gleichzeitig zu sortieren.
Quinn Taylor

Wie geht der obige NSSortDescriptor mit Nulldaten um? Müssen wir dem Deskriptor sagen, was er mit ihnen machen soll, wenn ja, wie?
Ash

17

Sie können auch Folgendes verwenden:

//Sort the array of items by  date
    [self.items sortUsingComparator:^NSComparisonResult(id obj1, id obj2){
        return [obj2.date compare:obj1.date];
    }];

Dies setzt jedoch voraus, dass das Datum NSDateeher als a gespeichert wirdNString , was kein Problem sein sollte. Vorzugsweise empfehle ich, die Daten auch im Rohformat zu speichern. Erleichtert die Manipulation in solchen Situationen.


9

Sie können Blöcke verwenden, um an Ort und Stelle zu sortieren:

sortedDatesArray = [[unsortedDatesArray sortedArrayUsingComparator: ^(id a, id b) {
    NSDate *d1 = [NSDate dateWithString: s1];
    NSDate *d2 = [NSDate dateWithString: s2];
    return [d1 compare: d2];
}];

Ich schlage vor, dass Sie alle Ihre Zeichenfolgen vor dem Sortieren in Datumsangaben konvertieren, um die Konvertierung nicht öfter als bei Datumsangaben durchzuführen. Jeder Sortieralgorithmus gibt Ihnen mehr Konvertierungen von Zeichenfolgen in Datumsangaben als die Anzahl der Elemente im Array (manchmal wesentlich mehr).

Ein bisschen mehr zum Sortieren von Blöcken: http://sokol8.blogspot.com/2011/04/sorting-nsarray-with-blocks.html


Dies ist eine Variante derselben suboptimalen Idee, die von @notoop vorgestellt wird. In jedem Fall ist die Konvertierung zuerst in NSDate definitiv der richtige Weg.
Quinn Taylor

Er hat meine Antwort einfach mit der Antwort von @ notoop versehen ..... es ist ziemlich unnötig, diese zu posten, wenn Sie mich fragen ....
TheCodingArt

Dies ist viel langsamer als das Parsen von Datumszeichenfolgen in ein Array von NSDate und das Sortieren des Arrays von NSDate, da die Zeichenfolge 2 * (n - 1) Mal zusätzlich analysiert wird. Das Parsen von Strings ist in der Regel eine schwere Aufgabe für die CPU.
CarlLee

5

In meinem Fall funktionierte Folgendes:

    NSArray * aUnsorted = [dataToDb allKeys];
    NSArray * arrKeys = [aUnsortiert sortiertArrayUsingComparator: ^ NSComparisonResult (id obj1, id obj2) {
        NSDateFormatter * df = [[NSDateFormatter alloc] init];
        [df setDateFormat: @ "TT-MM-JJJJ"];
        NSDate * d1 = [df dateFromString: (NSString *) obj1];
        NSDate * d2 = [df dateFromString: (NSString *) obj2];
        return [d1 vergleiche: d2];
    }];

Ich hatte ein Wörterbuch, in dem alle Schlüssel im Format TT-MM-JJJJ datiert waren. Und allKeys gibt die Wörterbuchschlüssel unsortiert zurück, und ich wollte die Daten in chronologischer Reihenfolge präsentieren.


5

Sie können verwenden sortedArrayUsingFunction:context:. Hier ist ein Beispiel:

NSComparisonResult dateSort(NSString *s1, NSString *s2, void *context) {
    NSDate *d1 = [NSDate dateWithString:s1];
    NSDate *d2 = [NSDate dateWithString:s2];
    return [d1 compare:d2];
}

NSArray *sorted = [unsorted sortedArrayUsingFunction:dateSort context:nil];

Wenn Sie a verwenden NSMutableArray, können Sie sortArrayUsingFunction:context:stattdessen verwenden.


9
Dies ist eine schlechte Idee - eine Vergleichsfunktion sollte schnell sein und nicht für jeden Vergleich NSDate-Objekte aus Zeichenfolgen erstellen müssen. Wenn Sie bereits - [NSDate compare:] verwenden, speichern Sie einfach die Daten im Array und verwenden Sie -sortedArrayUsingSelector: direkt.
Quinn Taylor

Ich denke, dies ist eine gute Lösung, wenn Sie Objekte sortieren, die bereits ein NSDate-Feld haben. Nein?
GnarlyDog

1
Wenn das Array bereits NSDateObjekte enthält , können Sie meine Antwort oben verwenden oder sogar verwenden -[NSMutableArray sortUsingComparator:], die in 10.6 hinzugefügt wurde.
Quinn Taylor

Wenn Sie ein Wörterbucharray verwenden, in dem ein Schlüsselwertobjekt für das Datum als NSString zusammen mit einigen anderen Schlüsselwertobjekten vorhanden ist, ist diese Lösung die bisher beste. Benötigen Sie nur eine kleine Änderung in der dateSort-Funktion. Daumen hoch! :)
Erfan

4

Sobald Sie eine haben NSDate, können Sie eine NSSortDescriptormit erstellen initWithKey:ascending:und dann sortedArrayUsingDescriptors:die Sortierung durchführen.


Dieser Ansatz funktioniert, aber die Verwendung von -sortedArrayUsingSelector: ist etwas einfacher und erfordert kein zusätzliches Objekt.
Quinn Taylor

Vor der Bearbeitung erwähnte die Frage "einen 'Datumsschlüssel'", also nahm ich an, dass dies wirklich eine Reihe von Objekten / Wörterbüchern war, die ein Datum als ein Feld hatten, keine Reihe von Rohdaten. In diesem Fall ist sortiertArrayUsingSelector: komplexer, da für die Suche eine benutzerdefinierte Sortierroutine geschrieben werden muss.
Smorgan

Ja, entschuldigen Sie die Verwirrung - ich habe diese Referenz bereinigt, da er nur sagte, dass er sein Array mit einem Datumsschlüssel speichert, und mir wurde klar, dass dies die Frage nur verwirrender machte. Bei einer komplexeren Datenstruktur haben Sie definitiv Recht mit der relativen Komplexität.
Quinn Taylor

2

Swift 3.0

myMutableArray = myMutableArray.sorted(by: { $0.date.compare($1.date) == ComparisonResult.orderedAscending })

1

Ändere das

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"beginDate" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];

Zu

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"Date" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];

Ändern Sie einfach den SCHLÜSSEL: Es muss Dateimmer sein

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.