Re: Using Set/Array KVC operators
Re: Using Set/Array KVC operators
- Subject: Re: Using Set/Array KVC operators
- From: Ken Thomases <email@hidden>
- Date: Fri, 19 Mar 2010 03:22:41 -0500
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@hidden)
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:
This email sent to email@hidden