Pregunta

Tengo una NSArray y me gustaría crear una nueva NSArray con los objetos de la matriz original que cumplir con ciertos criterios.Los criterios se decidió por una función que devuelve un BOOL.

Puedo crear una NSMutableArray, iterar a través de la matriz de origen y copia a través de los objetos que la función de filtro acepta y, a continuación, crear una inmutable versión de la misma.

Hay una manera mejor?

¿Fue útil?

Solución

NSArray y NSMutableArray proporcionar métodos para filtrar el contenido de la matriz. NSArray proporciona filteredArrayUsingPredicate: que devuelve una nueva matriz que contiene los objetos en el receptor, que coincide con el especificado predicado. NSMutableArray agrega filterUsingPredicate: en el que se evalúa el receptor del contenido contra el predicado especificado y deja sólo 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" }

Otros consejos

Hay un montón de maneras de hacer esto, pero por lejos el más bonito es sin duda el uso de [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 tan concisa como se pone.


Swift:

Para aquellos que trabajan con NSArrays en Swift, puede preferir esta aún más versión concisa:

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

filter es sólo un método de Array (NSArray es implícitamente puente de Swift Array).Toma un argumento:un cierre que tarda un objeto en el array y devuelve un Bool.En su cierre, acabo de volver de true para los objetos que desee en el filtrado de la matriz.

Si se OS X 10.6/iOS 4.0 o posterior, usted está probablemente mejor con bloques de NSPredicate.Ver -[NSArray indexesOfObjectsPassingTest:] o escribir su propia categoría para agregar una mano -select: o -filter: (método deejemplo).

Quieren a alguien para escribir esa categoría, probarlo, etc.?Echa un vistazo BlocksKit (matriz docs).Y hay muchos más ejemplos que se pueden encontrar, por ejemplo, buscando por ejemplo "nsarray bloque de categoría, seleccione".

Basada en una respuesta por Arcilla Puentes, aquí es un ejemplo de filtrado mediante bloques (cambiar yourArray a su matriz, nombre de la variable y testFunc para el nombre de su función de prueba):

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

Suponiendo que los objetos son todas del mismo tipo, se puede añadir un método como una categoría de su clase base que llama a la función que está utilizando para sus criterios.A continuación, crear un NSPredicate objeto que hace referencia a ese método.

En algunos categoría de definir el método que utiliza su función

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

A continuación, dondequiera que usted va a ser filtrado:

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

Por supuesto, si su función sólo se compara con propiedades accesible desde dentro de la clase puede ser más fácil para convertir la función de condiciones para un predicado de la cadena.

NSPredicate es nextstep la forma de construir 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 contiene el carácter c solo.

para hacer más fácil para recordar a aquellos que poco fondo sql es

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

1)select * from tbl --> colección

2)columna1 like '%a%' --> NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];

3)select * from tbl donde column1 like '%a%' -->

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

Espero que esto ayude

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

Puede descargar esta categoría aquí

Tu pedido esta biblioteca

https://github.com/BadChoice/Collection

Viene con un montón de fácil de la matriz de funciones de nunca escribir un bucle de nuevo

Así que usted puede hacer:

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

La Mejor y la Forma más fácil es crear este método Y la Matriz de Paso Y Valor:

- (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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top