NSArray Equivalent of Map
It only saves a couple lines, but I use a category on NSArray. You need to ensure your block never returns nil, but other than that it's a time saver for cases where -[NSArray valueForKey:]
won't work.
@interface NSArray (Map)
- (NSArray *)mapObjectsUsingBlock:(id (^)(id obj, NSUInteger idx))block;
@end
@implementation NSArray (Map)
- (NSArray *)mapObjectsUsingBlock:(id (^)(id obj, NSUInteger idx))block {
NSMutableArray *result = [NSMutableArray arrayWithCapacity:[self count]];
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[result addObject:block(obj, idx)];
}];
return result;
}
@end
Usage is much like -[NSArray enumerateObjectsWithBlock:]
:
NSArray *people = @[
@{ @"name": @"Bob", @"city": @"Boston" },
@{ @"name": @"Rob", @"city": @"Cambridge" },
@{ @"name": @"Robert", @"city": @"Somerville" }
];
// per the original question
NSArray *names = [people mapObjectsUsingBlock:^(id obj, NSUInteger idx) {
return obj[@"name"];
}];
// (Bob, Rob, Robert)
// you can do just about anything in a block
NSArray *fancyNames = [people mapObjectsUsingBlock:^(id obj, NSUInteger idx) {
return [NSString stringWithFormat:@"%@ of %@", obj[@"name"], obj[@"city"]];
}];
// (Bob of Boston, Rob of Cambridge, Robert of Somerville)
I've no idea what that bit of Ruby does but I think you are looking for NSArray's implementation of -valueForKey:. This sends -valueForKey:
to every element of the array and returns an array of the results. If the elements in the receiving array are NSDictionaries, -valueForKey:
is nearly the same as -objectForKey:
. It will work as long as the key doesn't start with an @
To summarize all other answers:
Ruby (as in the question):
array.map{|o| o.name}
Obj-C (with valueForKey
):
[array valueForKey:@"name"];
Obj-C (with valueForKeyPath
, see KVC Collection Operators):
[array valueForKeyPath:@"[collect].name"];
Obj-C (with enumerateObjectsUsingBlock
):
NSMutableArray *newArray = [NSMutableArray array];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[newArray addObject:[obj name]];
}];
Swift (with map, see closures)
array.map { $0.name }
And, there are a couple of libraries that allow you to handle arrays in a more functional way. CocoaPods is recommended to install other libraries.