問い合わせ言語を使って配列内のオブジェクトをフィルタリングしたい

for文でぐるぐるまわすのもいいけど、NSPredicateクラスと問い合わせ言語「Cocoa Predicates」を使うと便利。

問い合わせ言語を渡してNSPredicateオブジェクトを生成したのち、配列のfilteredArrayUsingPredicate:メソッドを呼び出して指定したオブジェクトのみをフィルタリングしてやります。

	// テストの点数
	NSArray *scores = [NSArray arrayWithObjects:
		[NSNumber numberWithInt:73],
		[NSNumber numberWithInt:26],
		[NSNumber numberWithInt:55],
		[NSNumber numberWithInt:38],
		[NSNumber numberWithInt:100],
		[NSNumber numberWithInt:81], nil];	
	NSArray *result;
	
	// 40点未満のものを抜き出す
	NSPredicate *lessThan40 = [NSPredicate predicateWithFormat:@"SELF < 40"];
	result = [scores filteredArrayUsingPredicate:lessThan40];
	NSLog(@"%@", result); //=> (26, 38)

	// 100点のものを抜き出す
	NSPredicate *equalTo100 = [NSPredicate predicateWithFormat:@"SELF = 100"];
	result = [scores filteredArrayUsingPredicate:equalTo100];
	NSLog(@"%@", result); //=> (100)

数値や文字列や日付以外のオブジェクトをフィルタリングしたい

Cocoa Predicatesの中ではキー値コーディングでアクセス可能なプロパティを参照できます。

	NSMutableArray *users = [NSMutableArray array];
	[users addObject:[[User alloc] initWithName:@"篠田" age:24]];
	[users addObject:[[User alloc] initWithName:@"前田" age:19]];
	[users addObject:[[User alloc] initWithName:@"大島" age:21]];
	
	NSArray *result;
	
	// 20歳以上のユーザを取得する
	NSPredicate *greaterThan20 = [NSPredicate predicateWithFormat:@"age >= 20"];
	result = [users filteredArrayUsingPredicate:greaterThan20];
	NSLog(@"%@", result); //=> (篠田, 大島)
	
	// 名前に「田」が含まれるユーザを取得する
	NSPredicate *nameContainsDa = [NSPredicate predicateWithFormat:
								   @"name CONTAINS '田'"];
	result = [users filteredArrayUsingPredicate:nameContainsDa];
	NSLog(@"%@", result); //=> (篠田, 前田)

配列から最大値、最小値を取り出す

NSPredicateとCocoa Predicatesの組み込み関数「max:」と「min:」を使えば、自前でfor文をぐるぐる回すことなく配列内の最大値、最小値を取得できます。

// 最大値、最小値を取り出す
NSArray *numbers = [NSArray arrayWithObjects:
					[NSNumber numberWithInt:3],
					[NSNumber numberWithInt:7],
					[NSNumber numberWithInt:2],
					[NSNumber numberWithInt:5],
					nil];
// 最大値
NSPredicate *maxPred = [NSPredicate predicateWithFormat:
						@"SELF == max:(%@)", numbers];
NSLog(@"%@", [numbers filteredArrayUsingPredicate:maxPred]); //=> [7]
// 最小値
NSPredicate *minPred = [NSPredicate predicateWithFormat:
						@"SELF == min:(%@)", numbers];
NSLog(@"%@", [numbers filteredArrayUsingPredicate:minPred]); //=> [2]

組み込み関数には「max:」や「min:」以外にもあって、例えば剰余を求める「modulus:by:」を利用して配列の中から偶数の値のみの取得することもできます。

NSArray *numbers = [NSArray arrayWithObjects:
					[NSNumber numberWithInt:1],	
					[NSNumber numberWithInt:2],
					[NSNumber numberWithInt:3],
					[NSNumber numberWithInt:4],
					[NSNumber numberWithInt:5],
					nil];
NSPredicate *evenPred = [NSPredicate predicateWithFormat:
						 @"modulus:by:(SELF, 2) == 0"];
NSLog(@"%@", [numbers filteredArrayUsingPredicate:evenPred]); //=> (2, 4)

それ以外の組み込み関数についてはNSExpressionクラスのマニュアルを参照のこと。まあ、何やらいろいろありますが使いどころがよくわからない関数がたくさんありますよ。

http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSExpression_Class/Reference/NSExpression.html#//apple_ref/doc/uid/TP30001190-CJBDJCJE

組み込み関数以外のメソッドを使ってオブジェクトをフィルタリングしたい

組み込み関数以外のメソッドを呼び出したい場合には「FUNCTION(...)」を利用します。

下記の例ではNSPredicateの中でNSString#componentsSeparatedByString:メソッドを呼び出しています。

NSArray *ss = [NSArray arrayWithObjects: @"base/a", @"base/bb", @"base/ccc", nil];
NSPredicate *pred = [NSPredicate predicateWithFormat:
	@"FUNCTION(SELF, 'componentsSeparatedByString:', '/')[1] == 'ccc'"];
NSLog(@"%@ => ccc: ", [ss filteredArrayUsingPredicate:pred]);