web-dev-qa-db-ja.com

NSArrayをObjective-Cの新しいNSArrayにフィルタリングする

NSArrayがあり、特定の条件を満たす元の配列のオブジェクトで新しいNSArrayを作成したいと思います。基準は、BOOLを返す関数によって決定されます。

NSMutableArrayを作成し、ソース配列を反復処理し、フィルター関数が受け入れるオブジェクトをコピーして、その不変バージョンを作成できます。

もっと良い方法はありますか?

117
lajos

NSArrayおよびNSMutableArrayは、配列の内容をフィルタリングするメソッドを提供します。 NSArrayfilteredArrayUsingPredicate:を提供します。これは、指定された述語に一致するレシーバー内のオブジェクトを含む新しい配列を返します。 NSMutableArrayが追加されますfilterUsingPredicate:指定された述語に対して受信者のコンテンツを評価し、一致するオブジェクトのみを残します。これらの方法を次の例に示します。

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

これを行う方法はたくさんありますが、最も近いのは間違いなく[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.
}]];

私はそれが得るほど簡潔だと思う。


迅速:

SwiftでNSArraysを使用している場合、これを好むかもしれませんさらに簡潔なバージョン:

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

filterArrayの単なるメソッドです(NSArrayはSwiftのArrayに暗黙的にブリッジされます)。引数を1つ取ります。配列内の1つのオブジェクトを取り、Boolを返すクロージャです。クロージャーで、フィルターされた配列に必要なオブジェクトに対してtrueを返すだけです。

100
Stuart

OS X 10.6/iOS 4.0以降を使用している場合、おそらくNSPredicateよりもブロックを使用した方が良いでしょう。見る - -[NSArray indexesOfObjectsPassingTest:] または、独自のカテゴリを作成して便利な-select: または -filter:メソッド( )。

他の誰かがそのカテゴリを書いたり、テストしたりしたいですか? BlocksKitarray docs )をご覧ください。そして、多くの例があります。 "nsarray block category select"

49
Clay Bridges

Clay Bridgesの回答に基づいて、ブロックを使用したフィルタリングの例を次に示します(yourArrayを配列変数名に、testFuncをテスト関数の名前に変更します):

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

オブジェクトがすべて同じタイプであると仮定すると、基準に使用している関数を呼び出すメソッドを基本クラスのカテゴリとして追加できます。次に、そのメソッドを参照するNSPredicateオブジェクトを作成します。

一部のカテゴリでは、関数を使用するメソッドを定義します

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

次に、フィルタリングする場所はどこでも:

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

もちろん、関数がクラス内から到達可能なプロパティとのみ比較する場合、関数の条件を述語文字列に変換する方が簡単かもしれません。

16
Ashley Clark

NSPredicateは、コレクションをフィルタリングする条件を構築するNeXTSTEPの方法です(NSArrayNSSetNSDictionary)。

たとえば、2つの配列arrfilteredarrを考えます。

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

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

filteredarrには、文字cのみを含むアイテムが必ずあります。

sQLのバックグラウンドが小さい人を覚えやすくするため

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

1)select * from tbl->コレクション

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

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

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

これが役立つことを願っています

3
Durai Amuthan.H

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

このカテゴリはこちらからダウンロードできます

2
skywinder

このライブラリをチェックアウトする

https://github.com/BadChoice/Collection

ループを二度と書くことのない簡単な配列関数がたくさん付属しています

だからあなたはちょうどすることができます:

NSArray* youngHeroes = [self.heroes filter:^BOOL(Hero *object) {
    return object.age.intValue < 20;
}];

または

NSArray* oldHeroes = [self.heroes reject:^BOOL(Hero *object) {
    return object.age.intValue < 20;
}];
0

最も簡単な方法は、このメソッドを作成し、配列と値を渡すことです。

- (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;
}
0
jalmatari