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 ([email protected])
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 [email protected]