2014-03-06 45 views
1

我有一個需要以特定方式進行過濾的字典數組。以例子來解釋最簡單。通過比較NSArray中的字典對象進行過濾

比方說,我有一個包含以下三個字典,其中一個數組@「的threadId」,@「主題」,@「MESSAGEID」是關鍵:

NSDictionary #1: 
@"threadId" : @"1234" 
@"subject" : @"hello" 
@"messageId" : @"0001" 

NSDictionary #2: 
@"threadId" : @"1234" 
@"subject" : @"hello" 
@"messageId" : @"0002" 

NSDictionary #3: 
@"threadId" : @"9101" 
@"subject" : @"goodbye" 
@"messageId" : @"0005" 

我考慮具有相同的任何字典@「threadId」和@「subject」的值是重複的,即使@「messageId」不同。因此,我認爲字典1和字典2是重複的,我想從上面的數組中刪除EITHER字典1或字典2(不是兩個)。換句話說,我想過濾所有三個字典的原始數組到一個新的數組,包含其他字典1和3或字典2和3.

到目前爲止我所做的所有嘗試都導致過度for循環,其中我試圖通過threadId對字典進行排序和分隔......但之後我陷入了比較部分。我已經看過謂詞過濾,但它看起來像只能刪除滿足特定條件的對象,而這些條件與其他對象的比較無關。 NSSet將不起作用,因爲我正在考慮重複的對象實際上並不重複。

我想知道是否有人可以建議執行此過濾的一般策略。

+0

可能的重複:http://stackoverflow.com/a/13499453/1301013您可能希望在操作數據集時使用NSPredicate。 –

回答

0

此代碼以便你的字典首先和檢查後,如果重複或沒有

NSSortDescriptor *sortDescriptor; 
//Order by threadId 
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"threadId" 
               ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)]; 

NSArray *arrayOrdered = [yourArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]]; 
NSMutableArray *arrayResult = [NSMutableArray array]; 
NSString* thread = nil; 
NSString* subj = nil; 
for (NSDictionary*dic in arrayOrdered) { 

    if ([thread length] == 0 && [subj length] == 0) { 
     thread = [dic objectForKey:@"threadId"]; 
     subj = [dic objectForKey:@"subject"]; 
    }else{ 

     if ([thread isEqualToString:[dic objectForKey:@"threadId"]]) { 
      if (![subj isEqualToString:[dic objectForKey:@"subject"]]) { 
       //We save it 
       [arrayResult addObject:dic]; 
      }else{ 
       //It´s already kept 
       NSLog(@"repeated dic"); 
      } 
     }else{ 
      [arrayResult addObject:dic]; 
     } 
    } 
} 
+0

謝謝!只需將線程和subj重置爲每次迭代都是零。很棒。 – jac300

0

你可以使用一個嵌套for循環,其中外層循環遍歷所有的元素(除了最後一個),並且內層循環遍歷從當前位置到結尾的所有元素。如果你找到一對相等的對,你可以將內環中的一個加到NSMutableSet。完成後,只需從陣列中刪除NSMutableSet中的所有元素。

0

我試圖做到這一點的所有迄今已導致過度的 循環,其中我試圖通過 的threadId進行排序和單獨的字典。

我認爲這將是策略,所以你是在正確的道路上。

在僞代碼中(不介意語法)我會這樣做;

String *threadid, *subject; 
// Important: Array must be already sorted (e.g. with a sortDescriptor) 
for (NSDictionary *dict in Array) 
{ 
    if (threadid == dict.threadid && subject == dict.subject) 
    { 
      // mark for removal 
    } 
    threadid = dict.threadid; 
    subject = dict.subject; 
} 

馬克去除將意味着增加的項目,以消除對新陣列,因爲你將不能夠同時被ennumerated它從一個數組中刪除對象。

+0

我認爲這隻會在第一個排序時才起作用,而這個代碼並沒有這樣做。答案並沒有說明它已經排序。 – Gavin

+0

@Gavin這就是爲什麼我粘貼用戶對'排序'的評論,但我同意,我會編輯答案。謝謝! – Merlevede

0

這應該工作:

NSArray *array = ...; // Your array of dictionaries 

// This is going to be the filtered array: 
NSMutableArray *unique = [NSMutableArray array]; 

// Set to keep track of all threadId/subject combinations added so far: 
NSMutableSet *set = [NSMutableSet set]; 

for (NSDictionary *d in array) { 
    // Create "sub-dictionary" that contains only the key/value pairs 
    // for determining uniqueness: 
    NSDictionary *tmp = [d dictionaryWithValuesForKeys:@[@"threadId", @"subject"]]; 
    // If we have don't have that combination already ... 
    if (![set containsObject:tmp]) { 
     // ... add the full dictionary to the new array ... 
     [unique addObject:d]; 
     // ... and the threadId/subject combination to the set. 
     [set addObject:tmp]; 
    } 
} 
0

簡單的循環與MutableSet檢查的唯一一個複合鍵。

NSMutableArray *filteredArray = [[NSMutableArray alloc] initWithCapacity:messages.count]; 
NSMutableSet *keysSet = [[NSMutableSet alloc] init]; 

for (NSDictionary *msg in messages) { 
    NSString *key = [NSString stringWithFormat:@"%@%@", msg[@"threadId"], msg[@"subject"]]; 
    if (![keysSet containsObject:key]) { 
     [filteredArray addObject:msg]; 
     [keysSet addObject:key]; 
    } 
}