3

说我有2 NSDictionaries,我不知道事先喜欢:如何使用ReactiveCocoa简化我的嵌套for循环?

NSDictionary *dictA = @{ @"key1" : @1, 
         @"key2" : @2 }; 

NSDictionary *dictB = @{ @"key1" : @"a string" }; 

我想找到的dictB按键和键或dictA值之间的第一场比赛。 dictB的每个密钥将是NSNumber或字符串。如果是数字,请尝试从的值dictA中找到匹配项。如果是字符串,请尝试从密钥dictA中找到匹配项。

使用for循环,它会看起来是这样的:

// shortened pseudo code: 
// id match = [dictA.rac_sequence compare with dictB.rac_sequence using block and return first match]; 
+0

您是否尝试过使用'filter:'?它似乎自然映射在这个计划上。 – allprog

+0

'过滤器:'在一个流上操作,它不会以递归方式在2个流/序列中操作项目。 – zakdances

回答

3

你基本上会:

id match; 
for (id key in dictA) { 
    for (id _key in dictB { 
     if ([_key is kindOfClass:NSNumber.class] && _key == dictA[key]) { 
      match = _key 
      goto outer; 
     } 
     else if ([_key is kindOfClass:NSString.class] && [_key isEqualToString:key]) { 
      match = _key 
      goto outer; 
     } 
    } 
}; 
outer:; 

NSString *message = match ? @"A match was found" : @"No match was found"; 
NSLog(message); 

使用RACSequenceRACStream方法,所以它看起来像ReactiveCocoa我怎么能改写这个喜欢创建字典的笛卡尔积,并对其进行选择。 ReactiveCocoa中没有默认的运算符,我知道这会为您做到这一点。 (在LINQ中有这样的操作符。)在RAC中,最简单的解决方案是使用scanWithStart:combine:方法来实现此操作。一旦笛卡尔准备就绪,filter:take:1操作将产生您选择的序列。

NSDictionary *adic = @{@"aa":@"vb", @"ab": @"va"}; 
NSDictionary *bdic = @{@"ba": @"va", @"bb":@"vb"};; 

RACSequence *aseq = adic.rac_keySequence; 
RACSequence *bseq = bdic.rac_keySequence; 

RACSequence *cartesian = [[aseq scanWithStart:nil combine:^id(id running, id next_a) { 
    return [bseq scanWithStart:nil combine:^id(id running, id next_b) { 
     return RACTuplePack(next_a, next_b); 
    }]; 
}] flatten]; 

RACSequence *filteredCartesian = [cartesian filter:^BOOL(RACTuple *value) { 
    RACTupleUnpack(NSString *key_a, NSString *key_b) = value; 
    // business logic with keys 
    return false; 
}]; 

RACSequence *firstMatch = [filteredCartesian take:1]; 
+0

写得非常优雅。 – zakdances

+0

@yourfriendzak这就是我喜欢RAC的原因。 :) – allprog

+0

我觉得这完全钝了。这就是为什么我不喜欢RAC。 ;) –