本周我的挑战是与objective-c中的块一起达成协议。我的脑子里有一些关于语法的东西。到那里。
我有以下代码以特定方式实现两个数组的合并(请参阅下面的代码中的注释)。
NSArray *keys = @[@"name", @"age"];
NSArray *data = @[
@[@"mark", @"36 years"],
@[@"matt", @"35 years"],
@[@"zoe", @"7 years"]
];
// desired outcome is
// @ { @"name" : @[@"mark", @"matt", @"zoe"],
// @"age" : @[@"36 years", @"35 years", @"7 years"]
// }
NSMutableArray *mergedData = [[NSMutableArray alloc] initWithCapacity:keys.count];
for (NSString *key in keys) {
NSLog(@"key: %@", key);
NSInteger keyIndex = [keys indexOfObject:key];
NSMutableArray *dataItemsForKey = [[NSMutableArray alloc] initWithCapacity:data.count];
for (NSArray *row in data) {
// double check the array count for row equals the expected count for keys - otherwise we have a 'match up' issue
if (row.count == keys.count) {
[dataItemsForKey addObject:[row objectAtIndex:keyIndex]];
}
}
[mergedData addObject:[NSDictionary dictionaryWithObject:dataItemsForKey forKey:key]];
}
NSLog (@"mergedData: %@", mergedData);
虽然这段代码运行良好,但为了我的挑战和学习,我想知道是否有一个更“优雅”(也就是更少的代码,更容易阅读)的方式来使用enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
?
我无法看到让它发挥作用的方法,但为了自我教育的利益,想知道那些在块和阵列中学到的东西是否可能有更优雅的解决方案。
答案 0 :(得分:1)
首先要说的是你的代码没有产生所需的输出。你得到一个包含两个词典的数组,每个词典都有一个键。
解决问题的一种方法是:
NSMutableDictionary* mergedData = [[NSMutableDictionary alloc] init];
[keys enumerateObjectsUsingBlock: ^(id key, NSUInteger keyIndex, BOOL *stop)
{
NSMutableArray* keyValues = [[NSMutableArray alloc] init];
for (NSArray* row in data)
{
[keyValues addObject: [row objectAtIndex: keyIndex]];
}
[mergedData setObject: keyValues forKey: key];
}];
如果行中没有足够的对象,则上面会抛出异常。您可以事先检查它或允许程序崩溃,这取决于您。
答案 1 :(得分:1)
我注意到的第一个问题是在枚举数组时要求当前对象的索引。这是浪费操作,因为在每次循环迭代时,您必须查看所有数组元素(可能是O(N))以查找对象的位置。
你可以这样做:
for(NSUInteger i=0; i<keys.count; i++)
{
NSString* key= keys[i];
<Rest of the code>
}
或者只是跟踪手动递增的索引:
NSUInteger i=0;
for (NSString *key in keys)
{
<Your code>
i++;
}
或者你想要的,使用 enumerateObjectsUsingBlock:,这是IMO在这种情况下最优雅的方式。这是一个例子:
NSMutableDictionary* dict=[NSMutableDictionary new];
[keys enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
NSMutableArray* fields=[NSMutableArray new];
for(NSArray* array in data)
{
[fields addObject: array[idx]];
}
[dict setObject: fields forKey: obj];
}];
如果您还不了解它的工作原理,可以进一步解释:
这样,在每次执行块时,您都可以知道哪个是当前对象( obj )和它的索引( idx )。 stop 仅用于停止枚举数组,但在这种情况下你不需要它(比如你要停止枚举,你设置* stop = YES)。在我的代码中,我只是将每个元素都放在 data 的索引 idx 中,然后构建一个数组,这是我放入字典的值,它有 obj (您在代码中称为 key )作为键。如有任何疑问,请随时通过评论提出任何澄清。