※修正。pluckとwhereを間違えてましたorz
Underscore.jsにarray.whereというとても便利なメソッドがある。
_.where(listOfPlays, {author: "Shakespeare", year: 1611});
//=> [{title: "Cymbeline", author: "Shakespeare", year: 1611},
{title: "The Tempest", author: "Shakespeare", year: 1611}]
あまりにも便利すぎるのでObjective-Cでも使いたくなったので実装した。
多分n番煎じだと思う。
cocoaにはvalueForKeyPath:という便利なアクセッサがあるので、入れ子になったNSDictionaryやオブジェクトなどのプロパティも比較できる。
NSArray+Where.h
@interface NSArray (Where)
- (NSArray*)whereUsingSelector:(SEL)selector value:(id)value;
- (NSArray*)whereForKeyPath:(NSString*)keyPath comparingSelector:(SEL)selector value:(id)value;
@end
NSArray+Where.m
# import <objc/message.h>
@implementation NSArray (Where)
- (NSArray *)whereUsingSelector:(SEL)selector value:(id)value
{
return [self whereForKeyPath:nil comparingSelector:selector value:value];
}
- (NSArray *)whereForKeyPath:(NSString *)keyPath comparingSelector:(SEL)selector value:(id)value
{
NSMutableArray *array = [NSMutableArray arrayWithCapacity:self.count];
for (id obj in self) {
id target = keyPath ? [obj valueForKeyPath:keyPath] : obj;
if ([target respondsToSelector:selector]){
if(objc_msgSend(target, selector, value)) {
[array addObject:target];
}
}
}
return [NSArray arrayWithArray:array];
}
@end
こんな感じで使えます。
NSARray+WhereTests.m
- (void)testBasic
{
NSArray *a = @[@"a",@"b",@"c",@"ab",@"cd",@"a"];
NSArray *p = [a whereUsingSelector:@selector(isEqualToString:) value:@"a"];
XCTAssert(p.count == 2, );
for (NSString *s in p) {
XCTAssert([s isEqualToString:@"a"], );
}
}
- (void)testKeyPath
{
NSArray *a = @[
@{@"hoge": @"hogeval"},
@{@"fuga" : @"fugaval"},
@{@"var" : @"varval"},
@{@"hoga" : @"hogaval"},
@{@"hoge": @"hogeval2"}
];
NSArray *p1 = [a whereUsingSelector:@selector(objectForKey:) value:@"hoge"];
XCTAssert(p1.count == 2, @"key hogeを持っているのは一つだけ");
NSArray *p2 = [a whereUsingSelector:@selector(isKindOfClass:) value:[NSDictionary class]];
XCTAssert(p2.count == a.count, @"全部辞書形");
NSArray *p3 = [a whereForKeyPath:@"hoge" comparingSelector:@selector(isEqualToString:) value:@"hogeval"];
XCTAssert(p3.count == 1, @"key hogeの値がhogevalなのは1つだけ");
}