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.

Postdienst14
quelle
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.)

Quinn Taylor
quelle
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];
vinzenzweber
quelle
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.

TheCodingArt
quelle
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

Kostiantyn Sokolinskyi
quelle
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.

Javier Calatrava Llavería
quelle
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.

notnoop
quelle
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.

smorgan
quelle
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 })
Abhishek Jain
quelle
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

user2339385
quelle