问题
I have an array of dictionaries that I need to filter in a very specific way. It's easiest to explain by example.
Let's say I have an array containing the following three dictionaries where @"threadId", @"subject", @"messageId" are keys:
NSDictionary #1:
@"threadId" : @"1234"
@"subject" : @"hello"
@"messageId" : @"0001"
NSDictionary #2:
@"threadId" : @"1234"
@"subject" : @"hello"
@"messageId" : @"0002"
NSDictionary #3:
@"threadId" : @"9101"
@"subject" : @"goodbye"
@"messageId" : @"0005"
I'm considering any dictionary that has the same value for @"threadId" and @"subject" to be duplicates, EVEN IF the @"messageId" is different. Thus, I'd consider dictionary 1 and dictionary 2 to be duplicates, and I'd like to remove EITHER dictionary 1 OR dictionary 2 (not both) from the above array. In other words, I'd like to filter the original array of all three dictionaries into a new array containing EITHER dictionaries 1 and 3 OR dictionaries 2 and 3.
All of my attempts to do this so far have resulted in excessive for loops, in which I attempt to sort and separate dictionaries by threadId... but then I get stuck at the comparison part. I've looked at filtering by predicate but that looks like it only removes objects that meet a particular criteria that has nothing to do with comparison with other objects. NSSet won't work because the objects I'm considering to be duplicates aren't actually duplicates.
I'm wondering if anyone could suggest a general strategy for performing this filtration.
回答1:
This code order your dictionaries firstly and after check if its repeated or no
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];
}
}
}
回答2:
You can do it using a nested for loop where the outer loop iterates over all of the elements (except the last one), and the inner loop iterates over all of the elements from the current position to the end. If you find a pair that are equal, you can add the one from the inner loop to an NSMutableSet
. Once you're done, you just remove all of the elements in the NSMutableSet
from the array.
回答3:
All of my attempts to do this so far have resulted in excessive for loops, in which I attempt to sort and separate dictionaries by threadId.
I think this would be the strategy, so you were on the right path.
In pseudo code (don't mind the syntax) I would do this;
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;
}
The mark for removal would imply adding the items to remove to a new array, because you won't be able to remove objects from an array while it is being ennumerated.
回答4:
This should work:
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];
}
}
回答5:
Simple loop with MutableSet for checking the uniqueness a compound key.
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];
}
}
来源:https://stackoverflow.com/questions/22236134/filtration-by-comparison-of-dictionary-objects-in-nsarray