NSArray
があり、特定の条件を満たす元の配列のオブジェクトで新しいNSArray
を作成したいと思います。基準は、BOOL
を返す関数によって決定されます。
NSMutableArray
を作成し、ソース配列を反復処理し、フィルター関数が受け入れるオブジェクトをコピーして、その不変バージョンを作成できます。
もっと良い方法はありますか?
NSArray
およびNSMutableArray
は、配列の内容をフィルタリングするメソッドを提供します。 NSArray
はfilteredArrayUsingPredicate:を提供します。これは、指定された述語に一致するレシーバー内のオブジェクトを含む新しい配列を返します。 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" }
これを行う方法はたくさんありますが、最も近いのは間違いなく[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でNSArray
sを使用している場合、これを好むかもしれませんさらに簡潔なバージョン:
nsArray = nsArray.filter { $0.shouldIKeepYou() }
filter
はArray
の単なるメソッドです(NSArray
はSwiftのArray
に暗黙的にブリッジされます)。引数を1つ取ります。配列内の1つのオブジェクトを取り、Bool
を返すクロージャです。クロージャーで、フィルターされた配列に必要なオブジェクトに対してtrue
を返すだけです。
OS X 10.6/iOS 4.0以降を使用している場合、おそらくNSPredicateよりもブロックを使用した方が良いでしょう。見る - -[NSArray indexesOfObjectsPassingTest:]
または、独自のカテゴリを作成して便利な-select:
または -filter:
メソッド( 例 )。
他の誰かがそのカテゴリを書いたり、テストしたりしたいですか? BlocksKit ( array docs )をご覧ください。そして、多くの例があります。 "nsarray block category select" 。
Clay Bridgesの回答に基づいて、ブロックを使用したフィルタリングの例を次に示します(yourArray
を配列変数名に、testFunc
をテスト関数の名前に変更します):
yourArray = [yourArray objectsAtIndexes:[yourArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [self testFunc:obj];
}]];
オブジェクトがすべて同じタイプであると仮定すると、基準に使用している関数を呼び出すメソッドを基本クラスのカテゴリとして追加できます。次に、そのメソッドを参照するNSPredicateオブジェクトを作成します。
一部のカテゴリでは、関数を使用するメソッドを定義します
@implementation BaseClass (SomeCategory)
- (BOOL)myMethod {
return someComparisonFunction(self, whatever);
}
@end
次に、フィルタリングする場所はどこでも:
- (NSArray *)myFilteredObjects {
NSPredicate *pred = [NSPredicate predicateWithFormat:@"myMethod = TRUE"];
return [myArray filteredArrayUsingPredicate:pred];
}
もちろん、関数がクラス内から到達可能なプロパティとのみ比較する場合、関数の条件を述語文字列に変換する方が簡単かもしれません。
NSPredicate
は、コレクションをフィルタリングする条件を構築するNeXTSTEPの方法です(NSArray
、NSSet
、NSDictionary
)。
たとえば、2つの配列arr
とfilteredarr
を考えます。
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]];
これが役立つことを願っています
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
このライブラリをチェックアウトする
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;
}];
最も簡単な方法は、このメソッドを作成し、配列と値を渡すことです。
- (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;
}