Ich habe eine NSArray
und ich möchte eine neue NSArray
mit Objekten aus dem ursprünglichen Array erstellen, die bestimmte Kriterien erfüllen. Das Kriterium wird von einer Funktion festgelegt, die eine BOOL
zurückgibt.
Ich kann eine NSMutableArray
erstellen, das Quellarray durchlaufen und die von der Filterfunktion akzeptierten Objekte kopieren und dann eine unveränderliche Version davon erstellen.
Gibt es einen besseren Weg?
NSArray
und NSMutableArray
bieten Methoden zum Filtern von Array-Inhalten. NSArray
bietet filtersArrayUsingPredicate: , das ein neues Array zurückgibt, das Objekte im Empfänger enthält, die dem angegebenen Prädikat entsprechen. NSMutableArray
fügt filterUsingPredicate: hinzu, das den Inhalt des Empfängers anhand des angegebenen Prädikats auswertet und nur übereinstimmende Objekte zurücklässt. Diese Methoden werden im folgenden Beispiel veranschaulicht.
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" }
Es gibt viele Möglichkeiten, dies zu tun, aber bei weitem wird [NSPredicate predicateWithBlock:]
mit Sicherheit verwendet:
NSArray *filteredArray = [array filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) {
return [object shouldIKeepYou]; // Return YES for each object you want in filteredArray.
}]];
Ich denke, das ist so knapp, wie es nur geht.
Für diejenigen, die in Swift mit NSArray
s arbeiten, bevorzugen Sie möglicherweise diese noch mehr prägnante Version:
nsArray = nsArray.filter { $0.shouldIKeepYou() }
filter
ist nur eine Methode für Array
(NSArray
ist implizit mit Swifts Array
verbunden). Es gibt ein Argument: eine Schließung, die ein Objekt im Array übernimmt und eine Bool
zurückgibt. In Ihrer Schließung geben Sie einfach true
für alle gewünschten Objekte im gefilterten Array zurück.
Wenn Sie OS X 10.6/iOS 4.0 oder höher verwenden, sind Sie mit Blocks wahrscheinlich besser als mit NSPredicate. Siehe -[NSArray indexesOfObjectsPassingTest:]
oder schreibe deine eigene Kategorie, um eine praktische -select:
- oder -filter:
-Methode ( example ) hinzuzufügen.
Möchten Sie, dass jemand anderes diese Kategorie schreibt, testet usw.? Check out BlocksKit ( array docs ). Und es gibt viele weitere Beispiele, die beispielsweise durch Suchen nach z. "nsarray block category select" .
Basierend auf einer Antwort von Clay Bridges, hier ein Beispiel für das Filtern mit Blöcken (ändern Sie yourArray
in den Namen Ihrer Array-Variablen und testFunc
in den Namen Ihrer Testfunktion):
yourArray = [yourArray objectsAtIndexes:[yourArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [self testFunc:obj];
}]];
Wenn Sie davon ausgehen, dass Ihre Objekte alle einen ähnlichen Typ haben, können Sie eine Methode als Kategorie ihrer Basisklasse hinzufügen, die die für Ihre Kriterien verwendete Funktion aufruft. Erstellen Sie dann ein NSPredicate-Objekt, das auf diese Methode verweist.
Definieren Sie in einigen Kategorien Ihre Methode, die Ihre Funktion verwendet
@implementation BaseClass (SomeCategory)
- (BOOL)myMethod {
return someComparisonFunction(self, whatever);
}
@end
Wo auch immer Sie filtern:
- (NSArray *)myFilteredObjects {
NSPredicate *pred = [NSPredicate predicateWithFormat:@"myMethod = TRUE"];
return [myArray filteredArrayUsingPredicate:pred];
}
Wenn Ihre Funktion nur mit Eigenschaften vergleichbar ist, die innerhalb Ihrer Klasse erreichbar sind, kann es natürlich einfacher sein, die Bedingungen der Funktion in eine Prädikatzeichenfolge umzuwandeln.
NSPredicate
ist die Methode von NeXTSTEP, Bedingungen zu erstellen, um eine Sammlung zu filtern (NSArray
, NSSet
, NSDictionary
).
Betrachten Sie zum Beispiel zwei Arrays arr
und filteredarr
:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];
filteredarr = [NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];
das gefilterte Haar wird sicherlich die Elemente enthalten, die nur den Buchstaben c enthalten.
um es leicht zu machen, sich an diejenigen zu erinnern, die ein wenig SQL-Hintergrund haben
*--select * from tbl where column1 like '%a%'--*
1) Wählen Sie * aus tbl -> collection aus
2) Spalte1 wie '% a%' -> NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];
3) Wähle * aus der Tabelle, wobei Spalte1 wie '% a%' -> steht
[NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];
Ich hoffe das hilft
NSArray + X.h
@interface NSArray (X)
/**
* @return new NSArray with objects, that passing test block
*/
- (NSArray *)filteredArrayPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate;
@end
NSArray + X.m
@implementation NSArray (X)
- (NSArray *)filteredArrayPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate
{
return [self objectsAtIndexes:[self indexesOfObjectsPassingTest:predicate]];
}
@end
Überprüfen Sie diese Bibliothek
https://github.com/BadChoice/Collection
Es gibt viele einfache Array-Funktionen, um nie wieder eine Schleife zu schreiben
Sie können also einfach folgendes tun:
NSArray* youngHeroes = [self.heroes filter:^BOOL(Hero *object) {
return object.age.intValue < 20;
}];
oder
NSArray* oldHeroes = [self.heroes reject:^BOOL(Hero *object) {
return object.age.intValue < 20;
}];
Der beste und einfachste Weg ist, diese Methode zu erstellen und Array und Wert zu übergeben:
- (NSArray *) filter:(NSArray *)array where:(NSString *)key is:(id)value{
NSMutableArray *temArr=[[NSMutableArray alloc] init];
for(NSDictionary *dic in self)
if([dic[key] isEqual:value])
[temArr addObject:dic];
return temArr;
}