J'ai une NSArray
et j'aimerais créer une nouvelle NSArray
avec des objets du tableau d'origine qui répondent à certains critères. Le critère est décidé par une fonction qui renvoie BOOL
.
Je peux créer une variable NSMutableArray
, parcourir le tableau source et copier sur les objets acceptés par la fonction de filtrage, puis en créer une version immuable.
Y a-t-il un meilleur moyen?
NSArray
et NSMutableArray
fournissent des méthodes pour filtrer le contenu des tableaux. NSArray
fournit filterArrayUsingPredicate: qui renvoie un nouveau tableau contenant les objets du récepteur qui correspondent au prédicat spécifié. NSMutableArray
ajoute filterUsingPsingicate: qui évalue le contenu du destinataire par rapport au prédicat spécifié et ne laisse que les objets correspondants. Ces méthodes sont illustrées dans l'exemple suivant.
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" }
Il existe de nombreuses façons de le faire, mais de loin le plus simple est sûrement d'utiliser [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.
}]];
Je pense que c'est à peu près aussi concis que possible.
Pour ceux qui travaillent avec NSArray
s dans Swift, vous préférerez peut-être cette version concise même plus:
nsArray = nsArray.filter { $0.shouldIKeepYou() }
filter
est simplement une méthode sur Array
(NSArray
est implicitement pontée vers Array
de Swift). Cela prend un argument: une fermeture qui prend un objet dans le tableau et retourne une Bool
. Dans votre clôture, retournez simplement true
pour tous les objets que vous voulez dans le tableau filtré.
Si vous utilisez OS X 10.6/iOS 4.0 ou une version ultérieure, vous êtes probablement mieux avec des blocs que NSPredicate. Voir -[NSArray indexesOfObjectsPassingTest:]
ou écrivez votre propre catégorie pour ajouter une méthode pratique -select:
ou -filter:
( exemple ).
Vous voulez que quelqu'un d'autre écrive cette catégorie, la teste, etc.? Départ BlocksKit ( Docs de tableau ). Et il y a beaucoup d’autres exemples à trouver, par exemple, en recherchant par exemple. "nsarray block category select" .
D'après une réponse de Clay Bridges, voici un exemple de filtrage à l'aide de blocs (remplacez yourArray
par le nom de votre variable de tableau et testFunc
par le nom de votre fonction de test):
yourArray = [yourArray objectsAtIndexes:[yourArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [self testFunc:obj];
}]];
En supposant que vos objets soient tous d'un type similaire, vous pouvez ajouter une méthode en tant que catégorie de leur classe de base qui appelle la fonction que vous utilisez pour vos critères. Créez ensuite un objet NSPredicate qui fait référence à cette méthode.
Dans certaines catégories, définissez votre méthode qui utilise votre fonction
@implementation BaseClass (SomeCategory)
- (BOOL)myMethod {
return someComparisonFunction(self, whatever);
}
@end
Ensuite, partout où vous filtrerez:
- (NSArray *)myFilteredObjects {
NSPredicate *pred = [NSPredicate predicateWithFormat:@"myMethod = TRUE"];
return [myArray filteredArrayUsingPredicate:pred];
}
Bien sûr, si votre fonction ne compare que les propriétés accessibles depuis votre classe, il sera peut-être plus simple de convertir les conditions de la fonction en chaîne de prédicat.
NSPredicate
est la façon dont NeXTSTEP a construit une condition pour filtrer une collection (NSArray
, NSSet
, NSDictionary
).
Par exemple, considérons deux tableaux arr
et filteredarr
:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];
filteredarr = [NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];
filterarr aura sûrement les éléments contenant le caractère c seul.
pour qu'il soit facile de se souvenir de ceux qui ont peu de fond SQL
*--select * from tbl where column1 like '%a%'--*
1) select * from tbl -> collection
2) colonne1 comme '% a%' -> NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];
3) select * from tbl où column1 comme '% a%' ->
[NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];
J'espère que ça aide
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
Commander cette bibliothèque
https://github.com/BadChoice/Collection
Il contient de nombreuses fonctions de tableau faciles à ne jamais écrire une boucle
Alors vous pouvez juste faire:
NSArray* youngHeroes = [self.heroes filter:^BOOL(Hero *object) {
return object.age.intValue < 20;
}];
ou
NSArray* oldHeroes = [self.heroes reject:^BOOL(Hero *object) {
return object.age.intValue < 20;
}];
La méthode la plus simple et la plus simple consiste à créer cette méthode, ainsi que Passe-tableau et valeur
- (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;
}