On Mar 18, 2010, at 6:15 PM, Sam Krishna wrote:

> I have two arrays of NSDictionaries that I'm trying to "uniquely merge" by 
> making sure that no two dictionaries have duplicate contents. I came up with 
> one solution, but I wanted to see if the community had an answer that 
> involved using one of the KVC array operators.

Just because?

By the way, I'm not seeing the "two arrays" you speak of.

> Here's the original code:
> 
>          // Get the array of dictionaries
>          NSArray *tempArray = [currentItem objectForKey:contactKey];
> 
>          // Walk it
>          for (NSDictionary *d in tempArray)
>          {
>            // Create the predicate and filter contacts_ based on it
>            NSPredicate *predicate = [NSPredicate predicateWithFormat:@"email 
> = %@", [d objectForKey:emailKey]];

If I'm understanding the nature of "emailKey", you probably want to replace the 
literal "email" in the predicate with a %K and format in the emailKey constant.

>            NSArray *filteredArray = [contacts_ 
> filteredArrayUsingPredicate:predicate];
> 
>            // If there's 0 results in the filtered array, add the current 
> dictionary to contacts_
>            if ([filteredArray count] == 0)
>            {
>              [contacts_ addObject:d];
>            }
>          }
>        }
> 
> What I'm specifically looking for is a way to compress the above code into a 
> line or two using the KVC array operators, specifically either 
> @distinctUnionOfArrays or @distinctUnionOfObjects to uniquely merge the two 
> arrays of dictionaries together. I'm trying to uniquely filter based on the 
> email key of the dictionaries, and it would be great to flatten alll this 
> code out.

Those operators don't work that way.  That is, "distinct"-ness is computed on 
the basis of the whole object, not by comparing some selected property of the 
object.  Therefore, unless you can guarantee that two dictionaries with 
equivalent "email" properties are also equivalent in whole, that can't work.

You can get a uniqued array of the email addresses, but not an array of the 
dictionaries that contain them.

Another way to think about your problem is that, for each unique contact email, 
you just want the first contact having that email.  You could rework the 
algorithm like so (typed in Mail):

        NSArray* contacts = [currentItem objectForKey:contactKey];
        NSArray* contactEmails = [contacts valueForKeyPath:[NSString 
stringWithFormat:@"@distinctUnionOfObjects.%@", emailKey]];

        for (NSString* email in contactEmails)
        {
                NSPredicate* predicate = [NSPredicate predicateWithFormat:@"%K 
= %@", emailKey, [d objectForKey:emailKey]];
                NSArray* contactsWithEmail = [contacts 
filteredArrayUsingPredicate:predicate]; // guaranteed to have at least one 
element
                [contacts_ addObject:[contactsWithEmail objectAtIndex:0]];
        }

It might be more efficient to use a parameterized predicate template created 
outside of the loop, and then do variable substitution inside the loop.  That 
avoids parsing the format string every time through.


Another approach more like your original algorithm, leveraging the power of 
predicates, might be:

        NSArray* contacts = [currentItem objectForKey:contactKey];

        for (;;)
        {
                // Predicate to find contacts whose emails are not in contacts_.
                NSPredicate* predicate = [NSPredicate predicateWithFormat:@"NOT 
%K IN %@", emailKey, [contacts_ valueForKey:emailKey]];
                // Get all contacts with emails which aren't already in the 
list.
                NSArray* contactsWithUnusedEmail = [contacts 
filteredArrayUsingPredicate:predicate];
                // If none, then done.
                if (![contactsWithUnusedEmail count])
                        break;
                // Add the first of those contacts and repeat
                [contacts_ addObject:[contactsWithUnusedEmail objectAtIndex:0]];
        }

I expect this one is probably slower, since: a) it gets the whole list of email 
addresses by iterating contacts_ each time through the loop, b) the predicate 
gets more complex each time, and c) evaluating the predicate effectively 
entails iterating all of the emails again, once per contact.  At a rough 
analysis, that's O(n^3).  I think the other algorithms are O(n^2).

Cheers,
Ken

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to