0

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.

1
  • You need to try combining them and then, if you have problems, show the code and seek help with that. Start with locating and logging duplicates. Then look at merging. Commented Feb 4, 2014 at 15:28

3 Answers 3

4

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];
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

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
    }       
}

Comments

1

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];
        }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.