filtrare NSArray in un nuovo NSArray in objective-c

Ho un NSArray e mi piacerebbe creare un nuovo NSArray con oggetti dell’array originale che soddisfano determinati criteri. Il criterio è deciso da una funzione che restituisce un BOOL .

Posso creare un NSMutableArray , scorrere l’array sorgente e copiare gli oggetti che la funzione filtro accetta e quindi creare una versione immutabile di esso.

C’è un modo migliore?

NSArray e NSMutableArray forniscono metodi per filtrare il contenuto dell’array. NSArray fornisce filteredArrayUsingPredicate: che restituisce un nuovo array contenente oggetti nel ricevitore che corrispondono al predicato specificato. NSMutableArray aggiunge filterUsingPredicate: che valuta il contenuto del destinatario rispetto al predicato specificato e lascia solo gli oggetti corrispondenti. Questi metodi sono illustrati nel seguente esempio.

 NSMutableArray *array = [NSMutableArray arrayWithObjects:@"Bill", @"Ben", @"Chris", @"Melissa", nil]; NSPredicate *bPredicate = [NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"]; NSArray *beginWithB = [array filteredArrayUsingPredicate:bPredicate]; // beginWithB contains { @"Bill", @"Ben" }. NSPredicate *sPredicate = [NSPredicate predicateWithFormat:@"SELF contains[c] 's'"]; [array filteredArrayUsingPredicate:sPredicate]; // array now contains { @"Chris", @"Melissa" } 

Ci sono molti modi per farlo, ma il più preciso è sicuramente usando [NSPredicate predicateWithBlock:] :

 NSArray *filteredArray = [array filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) { return [object shouldIKeepYou]; // Return YES for each object you want in filteredArray. }]]; 

Penso che sia abbastanza conciso come si arriva.


Swift:

Per chi lavora con NSArray s in Swift, potresti preferire questa versione ancora più concisa:

 nsArray = nsArray.filter { $0.shouldIKeepYou() } 

filter è solo un metodo su Array ( NSArray è implicitamente collegato a Swift’s Array ). Prende un argomento: una chiusura che prende un object nella matrice e restituisce un Bool . Nella tua chiusura, restituisci true per tutti gli oggetti che desideri nell’array filtrato.

Se sei OS X 10.6 / iOS 4.0 o successivo, probabilmente stai meglio con i blocchi di NSPredicate. Vedi -[NSArray indexesOfObjectsPassingTest:] o scrivi la tua categoria per aggiungere un pratico -select: o -filter: method ( esempio ).

Vuoi qualcun altro a scrivere quella categoria, testarla, ecc.? Scopri BlocksKit ( array docs ). E ci sono molti altri esempi che possono essere trovati, per esempio, cercando ad es. “Nsarray block category select” .

Sulla base di una risposta di Clay Bridges, ecco un esempio di filtraggio utilizzando i blocchi (cambia il tuo array con il nome della variabile dell’array e testFunc sul nome della funzione di test):

 yourArray = [yourArray objectsAtIndexes:[yourArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { return [self testFunc:obj]; }]]; 

Supponendo che i tuoi oggetti siano tutti di un tipo simile, potresti aggiungere un metodo come categoria della loro class base che chiama la funzione che stai utilizzando per i tuoi criteri. Quindi creare un object NSPredicate che si riferisce a quel metodo.

In alcune categorie definisci il tuo metodo che usa la tua funzione

 @implementation BaseClass (SomeCategory) - (BOOL)myMethod { return someComparisonFunction(self, whatever); } @end 

Quindi ovunque tu stia filtrando:

 - (NSArray *)myFilteredObjects { NSPredicate *pred = [NSPredicate predicateWithFormat:@"myMethod = TRUE"]; return [myArray filteredArrayUsingPredicate:pred]; } 

Naturalmente, se la tua funzione si confronta solo con proprietà raggiungibili dalla tua class, potrebbe essere più semplice convertire le condizioni della funzione in una stringa di predicato.

NSPredicate è il modo in cui nextstep costruisce le condizioni per filtrare una raccolta ( NSArray , NSSet , NSDictionary ).

Ad esempio, considera due array arr e filteredarr :

 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"]; filteredarr = [NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]]; 

il filteredarr avrà sicuramente gli oggetti che contengono solo il carattere c.

per rendere più facile ricordare quelli che hanno un piccolo background in sql

 *--select * from tbl where column1 like '%a%'--* 

1) seleziona * da tbl -> collezione

2) column1 come ‘% a%’ -> NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];

3) seleziona * da tbl dove colonna1 come ‘% a%’ ->

 [NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]]; 

Spero che aiuti

NSArray + Xh

 @interface NSArray (X) /** * @return new NSArray with objects, that passing test block */ - (NSArray *)filteredArrayPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate; @end 

NSArray + Xm

 @implementation NSArray (X) - (NSArray *)filteredArrayPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate { return [self objectsAtIndexes:[self indexesOfObjectsPassingTest:predicate]]; } @end 

Puoi scaricare questa categoria qui

Acquista questa libreria

https://github.com/BadChoice/Collection

Viene fornito con un sacco di semplici funzioni di array per non scrivere mai più un loop

Quindi puoi solo fare:

 NSArray* youngHeroes = [self.heroes filter:^BOOL(Hero *object) { return object.age.intValue < 20; }]; 

o

 NSArray* oldHeroes = [self.heroes reject:^BOOL(Hero *object) { return object.age.intValue < 20; }];