Reputation: 1595
I have an array which contains multiple Dictionaries each one with 3 keys (@"date"
, @"username"
, @"text"
).
What I want to check for, is whether the same user (@"username"
) exists in more than one dictionary in that Array. And, if she does, combine the text for those "duplicates" into one dictionary.
I have considered this answer to check for duplicates and this one but I cannot figure out how to combine these two.
Upvotes: 0
Views: 6217
Reputation: 37300
Jumping in here because although I think you should work on the code yourself first, I think Miro's answer is more complicated than the issue requires and though I like the idea of using predicates in Greg's answer, here's a 3rd solution that (1) wouldn't require you to change your data structure and (2) references the necessary loops...
The way I'd do it: Create an NSMutableArray then start adding the usernames in order. If the NSMutableArray already contains the username though, don't add another instance of the username, but instead merge the dictionary info.
ex.
// Note: I'm calling your array of user dictionaries userArray.
// Create a username array to store the usernames and check for duplicates
NSMutableArray *usernames = [[NSMutableArray alloc] init];
// Create a new userArray to store the updated dictionary info, merged
// entries et. al.
NSMutableArray *newUserArray = [[NSMutableArray alloc] init];
// Go through the array of user dictionaries
for (NSDictionary *userDict in userArray) {
// If the usernames array doesn't already contain the username,
// add it to both the usernames array and the newUserArray as is
if (![usernames containsObject:[userDict objectForKey:@"username"]]) {
[usernames addObject:[userDict objectForKey:@"username"]];
[newUserArray addObject:userDict];
}
// Otherwise, merge the userArray entries
else {
// Get a mutable copy of the dictionary entry at the first instance
// with this username
int indexOfFirstInstance = [usernames indexOfObject:[userDict objectForKey:@"username"]];
NSMutableDictionary *entry = [[newUserArray objectAtIndex:indexOfFirstInstance] mutableCopy];
// Then combine the "text" or whatever other values you wanted to combine
// by replacing the "text" value with the combined text.
// (I've done so with a comma, but you could also store the value in an array)
[entry setValue:[[entry objectForKey:@"text"] stringByAppendingString:[NSString stringWithFormat:@", %@", [userDict objectForKey:@"text"]]] forKey:@"text"];
// Then replace this newly merged dictionary with the one at the
// first instance
[newUserArray replaceObjectAtIndex:indexOfFirstInstance withObject:entry];
}
}
Upvotes: 4
Reputation: 25459
If you use NSMutableDictionary, NSMutableArray and NSMutableString you can do it with predicate like that:
NSMutableDictionary *d1 = [@{@"username": @"Greg", @"text" : [@"text 1" mutableCopy]} mutableCopy];
NSMutableDictionary *d2 = [@{@"username": @"Greg", @"text" : [@"text 2" mutableCopy]} mutableCopy];
NSMutableDictionary *d3 = [@{@"username": @"John", @"text" : [@"text 3" mutableCopy]} mutableCopy];
NSMutableArray *array = [@[d1, d2, d3] mutableCopy];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"username = %@", @"Greg"];
NSArray *filterArray = [array filteredArrayUsingPredicate:predicate];
NSMutableDictionary * firstDict = filterArray[0];
for (NSDictionary *d in filterArray)
{
if (firstDict != d)
{
[firstDict[@"text"] appendString:d[@"text"]];
[array removeObject:d];
}
}
Upvotes: 1
Reputation: 5337
Maybe something like this [untested] example? Loop through, maintain a hash of existing items, and if a duplicate is found then combine with existing and remove.
NSMutableArray main; // this should exist, with content
NSMutableDictionary *hash = [[NSMutableDictionary alloc] init];
// loop through, backwards, as we're attempting to modify array in place (risky)
for(int i = [main count] - 1; i >= 0; i--){
// check for existing
if(hash[main[i][@"username"]] != nil){
int existingIdx = [hash[main[i][@"username"]] integerValue]; // get existing location
main[existingIdx][@"text"] = [main[existingIdx][@"text"] stringByAppendingString:main[i][@"text"]]; // "combine text" .. or however you'd like to
[main removeObjectAtIndex:i]; // remove duplicate
} else {
[hash setValue:[[NSNumber alloc] initWithInt:i] forKey:main[i][@"username"]]; // mark existance, with location
}
}
Upvotes: 1