Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get distinct entity objects from NSMutableArray using NSPredicate in iPhone sdk [duplicate]

I have an NSMutableArray which has entity class object as its objects. Now I want to remove the distinct objects from it. Consider following example

Entity *entity = [[Entity alloc] init]; 
entity.iUserId = 1;
entity.iUserName = @"Giri"
[arr addObject:entity];

Entity *entity = [[Entity alloc] init]; 
entity.iUserId = 2;
entity.iUserName = @"Sunil"
[arr addObject:entity];

Entity *entity = [[Entity alloc] init]; 
entity.iUserId = 3;
entity.iUserName = @"Giri"
[arr addObject:entity];

Now I want only two objects in the Array by removing the duplicate iUserName. I know the way by iteration but I want it without iterating it like predicate or some other way. If anyone knows then please help me. I had tried using [arr valueForKeyPath:@"distinctUnionOfObjects.iUsername"]; but it does not return me the entired object.

This question is totally different than the questions which are asked previously. Previously asked question is for getting the distinct objects is correct but they uses looping & I don't want this. I want it from NSPredicate or any other simple option which avoids looping.

like image 820
Girish Avatar asked Oct 05 '22 01:10

Girish


1 Answers

EDIT: You can't do what you want to without looping over the array manually and building up a new array. The answer below won't work because it assumes that there are only at most two duplicates.

NSMutableArray *filteredArray = [NSMutableArray array];

for (Entity *entity in arr)
{
    BOOL hasDuplicate = [[filteredArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"iUserName == %@", entity.iUserName]] count] > 0;

    if (!hasDuplicate)
    {
        [filteredArray addObject:entity];
    }
}

This will look for duplicates in the filtered array as it builds it.

Begin Original Answer

You can't use an NSSet because the Entity instances would have to return NSOrderedSame in compareTo:, which isn't a good idea since you shouldn't use names as unique identifiers.

You can use predicates, but they'll still loop over the array in an O(n^2) time without some optimization.

NSArray *filteredArray = [arr filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(Entity *evaluatedObject, NSDictionary *bindings) {
    return [[arr filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"iUserName == %@", evaluatedObject.iUserName]] count] > 1;
}]];

That'll work fine. You could make it even faster by sorting the array by the iUserName property first and doing a linear scan over the sorted array (stopping when you see the first duplicate). That's a lot of work if you're dealing with small sample sizes (say, under ten thousand or so). It's probably not worth your time, so just use the code above.

like image 123
Ash Furrow Avatar answered Oct 12 '22 07:10

Ash Furrow