Ordina NSArray di stringhe di data o oggetti


86

Ho un messaggio NSArrayche contiene stringhe di data (ad esempio NSString) come questo: "Thu, 21 May 09 19:10:09 -0700"

Devo ordinare NSArrayper data. Ho pensato prima di convertire la stringa della data in un NSDateoggetto, ma sono rimasto bloccato lì su come ordinare in base NSDateall'oggetto.

Grazie.


Ricodificato poiché è correlato al framework Foundation e non specifico per iPhone.
Quinn Taylor

Risposte:


110

Memorizza le date come NSDateoggetti in un array NS (mutevole), quindi utilizza -[NSArray sortedArrayUsingSelector:o -[NSMutableArray sortUsingSelector:]e passa @selector(compare:)come parametro. Il -[NSDate compare:]metodo ordinerà le date in ordine crescente per te. Questo è più semplice che creare una NSSortDescriptor, e molto più semplice che scrivere la tua funzione di confronto. (gli NSDateoggetti sanno come confrontarsi tra loro almeno nel modo più efficiente che potremmo sperare di ottenere con il codice personalizzato.)


11
Non è chiaro se la domanda originale fosse relativa all'ordinamento di un array di date o all'ordinamento di un array di oggetti che hanno un campo data. Questo è l'approccio più semplice se è il primo, ma se è il secondo, NSSortDescriptor è la strada da percorrere.
smorgan

@smorgan come gestisce NSSortDescriptor le date nulle?
Ash

Grazie per il tuo aiuto, penso che dovremmo leggere di più in Apple Docs ma sembra così noioso, finché non lo usi.
Abo3atef

1
Potresti mostrarlo in uno snippet di codice come esempio? Grazie in anticipo.
uplearnedu.com

115

Se ho un NSMutableArraydi oggetti con un campo "beginDate" di tipo, NSDatesto usando un NSSortDescriptorcome di seguito:

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

3
So che è passato molto tempo (quando la risposta precedente è stata accettata non poteva ancora esserci alcun NSSortDescriptor), ma per un uso futuro questa dovrebbe essere la risposta corretta.
Vive

1
Questa è una soluzione fantastica. ha risolto il mio problema in poche righe di codice Grazie
mille

1
Davvero ... sono rimasto davvero scioccato che abbia funzionato alla prima esecuzione! Pensavo che initWithKey fosse riservato ai dizionari in cui è definita la chiave, ma tutto ciò che devi fare è fare riferimento a una proprietà in un array di oggetti? Lascia che la luce risplenda vinzenzweberskavitchski !!
whyoz

NSSortDescriptor è in circolazione da OS X 10.3, alla fine del 2003. Questo è uno scenario leggermente diverso, in cui la data è un campo in un altro oggetto. Con un'API ancora più moderna, potresti anche usare -[NSMutableArray sortUsingComparator:](10.6+) e passare un blocco che restituisce il risultato della chiamata -compare:sui due campi. Probabilmente sarebbe più veloce che chiamare -valueForKey:ogni oggetto. Puoi anche usare -sortWithOptions:usingComparator:e passare opzioni per ordinare contemporaneamente.
Quinn Taylor

in che modo il suddetto NSSortDescriptor gestisce le date nulle? Dobbiamo dire al dissacratore cosa farne se è così, come?
Ash

17

Puoi anche usare qualcosa di simile al seguente:

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

Ma questo presuppone che la data sia memorizzata come una NSDateaNString , il che non dovrebbe essere un problema da creare / fare. Preferibilmente, consiglio anche di archiviare i dati nel suo formato grezzo. Rende più facile manipolare in situazioni come questa.


9

Puoi utilizzare i blocchi per ordinare in posizione:

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

Ti suggerisco di convertire tutte le tue stringhe in date prima dell'ordinamento per non eseguire la conversione più volte di quante siano le voci di data. Qualsiasi algoritmo di ordinamento ti darà più conversioni da stringa a data rispetto al numero di elementi nell'array (a volte sostanzialmente di più)

un po 'di più sull'ordinamento dei blocchi: http://sokol8.blogspot.com/2011/04/sorting-nsarray-with-blocks.html


Questa è una variante della stessa idea subottimale presentata da @notoop. In ogni caso, convertire prima in NSDate è sicuramente la strada da percorrere.
Quinn Taylor

Fondamentalmente ha appena messo la mia risposta con la risposta di @ notoop ..... abbastanza inutile postare due volte quelli se me lo chiedi ....
TheCodingArt

Questo è molto più lento dell'analisi delle stringhe di data nell'array di NSDate e quindi dell'ordinamento dell'array di NSDate, perché ci sarà 2 * (n - 1) volte un'analisi extra della stringa. L'analisi delle stringhe è generalmente un lavoro pesante sulla CPU.
CarlLee

5

Quello che ha funzionato nel mio caso è stato il seguente:

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

Avevo un dizionario, dove tutte le chiavi dovevano le date nel formato gg-MM-aaaa. E allKeys restituisce le chiavi del dizionario non ordinate e volevo presentare i dati in ordine cronologico.


5

Puoi usare sortedArrayUsingFunction:context:. Ecco un esempio:

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

Quando usi a NSMutableArray, puoi usare sortArrayUsingFunction:context:invece.


9
Questa è una cattiva idea: una funzione di confronto dovrebbe essere veloce e non dovrebbe creare oggetti NSDate da stringhe per ogni confronto. Se stai già utilizzando - [NSDate compare:], memorizza semplicemente le date nell'array e usa -sortedArrayUsingSelector: direttamente.
Quinn Taylor

Penso che questa sia una buona soluzione se stai ordinando oggetti che hanno già un campo NSDate. No?
GnarlyDog

1
Se l'array contiene già NSDateoggetti, puoi usare la mia risposta sopra, o anche usare -[NSMutableArray sortUsingComparator:], che è stata aggiunta nella 10.6.
Quinn Taylor

Se stai utilizzando una matrice di dizionario in cui è presente un oggetto valore-chiave per la data come NSString insieme ad altri oggetti valore-chiave, questa soluzione è la migliore finora. Ho solo bisogno di una piccola modifica all'interno della funzione dateSort. Pollice su! :)
Erfan

4

Una volta che hai un NSDate, puoi creare un NSSortDescriptorcon initWithKey:ascending:e poi usarlo sortedArrayUsingDescriptors:per fare l'ordinamento.


Questo approccio funzionerà, ma l'uso di -sortedArrayUsingSelector: è un po 'più semplice e non richiede la creazione di un oggetto aggiuntivo.
Quinn Taylor

Prima della modifica, la domanda menzionava "una chiave di 'data'", quindi ho pensato che fosse in realtà un array di oggetti / dizionari che avevano una data come campo, non un array di date non elaborate. In tal caso, SortArrayUsingSelector: è più complesso, poiché richiede la scrittura di una routine di ordinamento personalizzata per eseguire la ricerca.
smorgan

Sì, scusa per la confusione - ho ripulito quel riferimento poiché stava solo dicendo che stava memorizzando il suo array con una chiave di "data", e ho capito che rendeva la domanda più confusa. Hai decisamente ragione sulla complessità relativa data una struttura dati più complessa.
Quinn Taylor

2

Swift 3.0

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

1

Cambia questo

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

Per

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

Basta cambiare la CHIAVE: deve essere Datesempre

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.