objective c sierra Filtrando NSArray em um novo NSArray em object-c




xcode ios sierra (8)

Eu tenho um NSArray e gostaria de criar um novo NSArray com objetos do array original que atendem a determinados critérios. Os critérios são decididos por uma função que retorna um BOOL .

Eu posso criar um NSMutableArray , iterar através da matriz de origem e copiar os objetos que a função de filtro aceita e, em seguida, criar uma versão imutável dele.

Existe uma maneira melhor?


Existem muitas maneiras de fazer isso, mas de longe o mais [NSPredicate predicateWithBlock:] é certamente usar o [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.
}]];

Eu acho que é tão conciso quanto parece.

Rápido:

Para aqueles que trabalham com o NSArray s no Swift, você pode preferir esta versão ainda mais concisa:

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

filter é apenas um método no Array (o NSArray é implicitamente vinculado ao Array do Swift). Leva um argumento: um fechamento que leva um objeto na matriz e retorna um Bool . Em seu fechamento, apenas retorne true para qualquer objeto que você queira na matriz filtrada.


NSPredicate é o caminho do nextstep de construir condições para filtrar uma coleção ( NSArray , NSSet , NSDictionary ).

Por exemplo, considere dois arrays arr e filteredarr :

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];

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

o filtrarr certamente terá os itens que contém o caractere c sozinho.

para tornar mais fácil lembrar aqueles que pouco fundo sql é

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

1) selecione * da coleção tbl ->

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

3) selecione * de tbl onde coluna1 como '% a%' ->

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

Eu espero que isso ajude


A maneira melhor e mais fácil é criar este método e passar matriz e 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;
}

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

Você pode baixar esta categoria aqui



NSArray e NSMutableArray fornecem métodos para filtrar o conteúdo da matriz. NSArray fornece NSArray : que retorna um novo array contendo objetos no receptor que correspondem ao predicado especificado. NSMutableArray adiciona filterUsingPredicate: que avalia o conteúdo do receptor em relação ao predicado especificado e deixa apenas objetos que correspondem. Esses métodos são ilustrados no exemplo a seguir.

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" }

Checkout esta biblioteca

https://github.com/BadChoice/Collection

Ele vem com muitas funções fáceis de array para nunca mais escrever um loop

Então você pode apenas fazer:

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

Supondo que seus objetos sejam todos de um tipo semelhante, você poderia adicionar um método como uma categoria de sua classe base que chama a função que você está usando para seus critérios. Em seguida, crie um objeto NSPredicate que se refira a esse método.

Em alguma categoria defina seu método que usa sua função

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

Então, onde quer que você esteja filtrando:

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

Naturalmente, se a sua função só comparar com propriedades alcançáveis ​​de dentro da sua classe, pode ser mais fácil converter as condições da função em uma cadeia de predicados.





cocoa