问题描述
|
给定“ 0”个“ 1”个对象(包含相似的对象和键),是否可以将执行映射写入指定键的数组?例如,在Ruby中,可以使用:
array.map(&:name)
解决方法
更新:如果您使用的是Swift,请参见地图。
BlocksKit是一个选项:
NSArray *new = [stringArray bk_map:^id(NSString *obj) {
return [obj stringByAppendingString:@\".png\"];
}];
下划线是另一种选择。有一个“ 4”功能,这是网站上的一个示例:
NSArray *tweets = Underscore.array(results)
// Let\'s make sure that we only operate on NSDictionaries,you never
// know with these APIs ;-)
.filter(Underscore.isDictionary)
// Remove all tweets that are in English
.reject(^BOOL (NSDictionary *tweet) {
return [tweet[@\"iso_language_code\"] isEqualToString:@\"en\"];
})
// Create a simple string representation for every tweet
.map(^NSString *(NSDictionary *tweet) {
NSString *name = tweet[@\"from_user_name\"];
NSString *text = tweet[@\"text\"];
return [NSString stringWithFormat:@\"%@: %@\",name,text];
})
.unwrap;
,它只保存几行,但是我在NSArray上使用了一个类别。您需要确保您的代码块永远不会返回nil,但除此之外,对于-[NSArray valueForKey:]
不起作用的情况,它可以节省时间。
@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
用法很像-[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)
,我不知道Ruby的功能如何,但是我认为您正在寻找NSArray的-valueForKey:的实现。这会向数组的每个元素发送“ 10”,并返回结果数组。如果接收数组中的元素是NSDictionaries,则ѭ10与ѭ12几乎相同。只要键不是以ѭ13开头,它将起作用
,总结所有其他答案:
Ruby(在问题中):
array.map{|o| o.name}
Obj-C(带有valueForKey):
[array valueForKey:@\"name\"];
Obj-C(带有valueForKeyPath,请参阅KVC集合运算符):
[array valueForKeyPath:@\"[collect].name\"];
Obj-C(带有enumerateObjectsUsingBlock):
NSMutableArray *newArray = [NSMutableArray array];
[array enumerateObjectsUsingBlock:^(id obj,BOOL *stop) {
[newArray addObject:[obj name]];
}];
Swift(带有地图,请参见闭包)
array.map { $0.name }
而且,有几个库可让您以更实用的方式处理数组。建议可可豆荚安装其他库。
,我认为valueForKeyPath是一个不错的选择。
坐在下面有很酷的例子。希望对您有所帮助。
http://kickingbear.com/blog/archives/9
一些例子:
NSArray *names = [allEmployees valueForKeyPath: @\"[collect].{daysOff<10}.name\"];
NSArray *albumCovers = [records valueForKeyPath:@\"[collect].{artist like \'Bon Iver\'}.<NSUnarchiveFromDataTransformerName>.albumCoverImageData\"];
,我不是Ruby专家,所以我不是100%自信地回答正确,但是基于这样的解释,“'map \'对数组中的所有内容都会执行某些操作,并生成一个包含结果的新数组,我认为您可能想要的是:
NSMutableArray *replacementArray = [NSMutableArray array];
[existingArray enumerateObjectsUsingBlock:
^(NSDictionary *dictionary,BOOL *stop)
{
NewObjectType *newObject = [something created from \'dictionary\' somehow];
[replacementArray addObject:newObject];
}
];
因此,您正在使用OS X 10.6 / iOS 4.0中对\'blocks'(更笼统地说是闭包)的新支持,以对数组中的所有内容执行block中的内容。您选择执行一些操作,然后将结果添加到单独的数组中。
如果您希望支持10.5或iOS 3.x,则可能需要考虑将相关代码放入对象中并使用makeObjectsPerformSelector:或者,更糟糕的是,使用ѭ21doing进行数组的手动迭代。
,@implementation NSArray (BlockRockinBeats)
- (NSArray*)mappedWithBlock:(id (^)(id obj,NSUInteger idx))block {
NSMutableArray* result = [NSMutableArray arrayWithCapacity:self.count];
[self enumerateObjectsUsingBlock:^(id currentObject,NSUInteger index,BOOL *stop) {
id mappedCurrentObject = block(currentObject,index);
if (mappedCurrentObject)
{
[result addObject:mappedCurrentObject];
}
}];
return result;
}
@end
在发布的几个答案上略有改善。
检查是否为零-您可以在映射时使用nil删除对象
方法名称更好地反映了该方法不会修改其调用的数组
这更多是一种样式,但我已经改善了IMO的参数名称
点语法的计数
,对于Objective-C,我将ObjectiveSugar库添加到以下答案列表中:https://github.com/supermarin/ObjectiveSugar
另外,它的标语是“适用于人类的ObjectiveC附加功能。Ruby风格。”这应该非常适合OP;
我最常见的用例是将服务器调用返回的字典映射到较简单的对象数组,例如从您的NSDictionary帖子中获取NSString ID的NSArray:
NSArray *postIds = [results map:^NSString*(NSDictionary* post) {
return [post objectForKey:@\"post_id\"];
}];
,对于Objective-C,我将“高阶函数”添加到此答案列表中:https://github.com/fanpyi/Higher-Order-Functions;
有一个JSON数组studentJSONList像这样:
[
{\"number\":\"100366\",\"name\":\"Alice\",\"age\":14,\"score\":80,\"gender\":\"female\"},{\"number\":\"100368\",\"name\":\"Scarlett\",\"age\":15,\"score\":90,{\"number\":\"100370\",\"name\":\"Morgan\",\"age\":16,\"score\":69.5,\"gender\":\"male\"},{\"number\":\"100359\",\"name\":\"Taylor\",\"score\":86,{\"number\":\"100381\",\"name\":\"John\",\"age\":17,\"score\":72,\"gender\":\"male\"}
]
//studentJSONList map to NSArray<Student *>
NSArray *students = [studentJSONList map:^id(id obj) {
return [[Student alloc]initWithDictionary:obj];
}];
// use reduce to get average score
NSNumber *sum = [students reduce:@0 combine:^id(id accumulator,id item) {
Student *std = (Student *)item;
return @([accumulator floatValue] + std.score);
}];
float averageScore = sum.floatValue/students.count;
// use filter to find all student of score greater than 70
NSArray *greaterthan = [students filter:^BOOL(id obj) {
Student *std = (Student *)obj;
return std.score > 70;
}];
//use contains check students whether contain the student named \'Alice\'
BOOL contains = [students contains:^BOOL(id obj) {
Student *std = (Student *)obj;
return [std.name isEqual:@\"Alice\"];
}];
,Swift引入了新的地图功能。
这是文档中的一个示例:
let digitNames = [
0: \"Zero\",1: \"One\",2: \"Two\",3: \"Three\",4: \"Four\",5: \"Five\",6: \"Six\",7: \"Seven\",8: \"Eight\",9: \"Nine\"
]
let numbers = [16,58,510]
let strings = numbers.map {
(var number) -> String in
var output = \"\"
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
}
// strings is inferred to be of type String[]
// its value is [\"OneSix\",\"FiveEight\",\"FiveOneZero\"]
map函数采用闭包,该闭包返回任何类型的值,并将数组中的现有值映射到此新类型的实例。