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。 ;) –