objective-c - programación - versiones de objective c
filtrando NSArray en un nuevo NSArray en objetivo-c (8)
Tengo un NSArray
y me gustaría crear un nuevo NSArray
con objetos de la matriz original que cumplan con ciertos criterios. El criterio es decidido por una función que devuelve un BOOL
.
Puedo crear un NSMutableArray
, recorrer el conjunto de origen y copiar los objetos que acepta la función de filtro y luego crear una versión inmutable del mismo.
¿Hay una mejor manera?
Basado en una respuesta de Clay Bridges, aquí hay un ejemplo de filtrado usando bloques (cambie su matriz a su nombre de variable de matriz y testFunc
al nombre de su función de prueba):
yourArray = [yourArray objectsAtIndexes:[yourArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [self testFunc:obj];
}]];
Hay muchas maneras de hacerlo, pero con mucho, lo más seguro es utilizar [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.
}]];
Creo que es lo más conciso posible.
Rápido:
Para aquellos que trabajan con NSArray
s en Swift, puede preferir esta versión aún más concisa:
nsArray = nsArray.filter { $0.shouldIKeepYou() }
filter
es solo un método en Array
( NSArray
está puenteado implícitamente con Array
de Swift). Se necesita un argumento: un cierre que toma un objeto en la matriz y devuelve un Bool
. En su cierre, simplemente devuelva true
para cualquier objeto que desee en la matriz filtrada.
Pagar esta biblioteca
https://github.com/BadChoice/Collection
Viene con muchas funciones de matriz fáciles de nunca escribir un bucle de nuevo
Entonces puedes hacer lo siguiente:
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;
}];
Si es OS X 10.6 / iOS 4.0 o posterior, probablemente esté mejor con bloques que NSPredicate. Consulte -[NSArray indexesOfObjectsPassingTest:]
o escriba su propia categoría para agregar un práctico -select:
o -filter:
método ( example ).
¿Quieres que alguien más escriba esa categoría, la pruebe, etc.? Echa un vistazo a BlocksKit ( documentos de matriz ). Y hay muchos más ejemplos que se pueden encontrar, por ejemplo, buscando, por ejemplo, "nsarray block category select" .
Suponiendo que sus objetos son todos de un tipo similar, puede agregar un método como categoría de su clase base que llama a la función que está utilizando para sus criterios. Luego crea un objeto NSPredicate que se refiera a ese método.
En alguna categoría define tu método que usa tu función
@implementation BaseClass (SomeCategory)
- (BOOL)myMethod {
return someComparisonFunction(self, whatever);
}
@end
Entonces, donde sea que estés filtrando:
- (NSArray *)myFilteredObjects {
NSPredicate *pred = [NSPredicate predicateWithFormat:@"myMethod = TRUE"];
return [myArray filteredArrayUsingPredicate:pred];
}
Por supuesto, si su función solo se compara con las propiedades accesibles desde dentro de su clase, puede ser más fácil convertir las condiciones de la función en una cadena de predicados.
NSArray
y NSMutableArray
proporcionan métodos para filtrar los contenidos de la matriz. NSArray
proporciona filteredArrayUsingPredicate: que devuelve una nueva matriz que contiene objetos en el receptor que coinciden con el predicado especificado. NSMutableArray
agrega filterUsingPredicate: que evalúa el contenido del receptor contra el predicado especificado y deja solo los objetos que coinciden. Estos métodos se ilustran en el siguiente ejemplo.
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" }
NSPredicate
es la forma en que nextstep construye la condición para filtrar una colección ( NSArray
, NSSet
, NSDictionary
).
Por ejemplo, considere dos matrices arr
y filteredarr
:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];
filteredarr = [NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];
el filteredarr seguramente tendrá los elementos que contienen el carácter c solo.
para que sea fácil recordar aquellos que tienen poco fondo sql
*--select * from tbl where column1 like ''%a%''--*
1) seleccione * de tbl -> colección
2) column1 como ''% a%'' -> NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];
3) selecciona * de tbl donde column1 como ''% a%'' ->
[NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];
espero que esto ayude
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