JAHelia
JAHelia

Reputation: 7922

a predicate to filter out similar objects by an attribute

I"m performing a regular NSFetchRequest without any predicate to fetch 100 managed objects (flights), each Flight entity has an attribute of type NSString named (flightCode) and this attribute is not unique, so 2 flight objects may have the same flightCode . However, I want to fetch all flight objects filtering out flights that have the same flightCode by taking only one flight from similarities, i.e.

if the fetch request returned 5 flights as follows:

flight1: flightCode = ABC

flight2: flightCode = AA

flight3: flightCode = ABC

flight4: flightCode = ABC

flight5: flightCode = DEF

then the fetch request must filter out any two of the 3 flights that have the flightCode ABC and take only any random one of these 3.

what is the required NSPredicate for this filtering ?

p.s. flights: 1, 3 & 4 may be different in other attributes, i.e. flight1's name may be different from flight3's name.

thanks in advance.

Upvotes: 1

Views: 135

Answers (2)

rob mayoff
rob mayoff

Reputation: 385590

If you just want a list of all distinct flight codes, this may do what you want:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Flight"
    inManagedObjectContext:moc];
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entity.name];
request.resultType = NSDictionaryResultType;
request.returnsDistinctResults = YES;
request.propertiesToFetch = @[ entity.propertiesByName[@"flightCode"] ];

Note that returnsDistinctResults only works if propertiesToFetch is set, and propertiesToFetch only works if resultType is NSDictionaryResultType.

REVISED

If you want full Flight objects, but only one for each distinct flight code, I don't think you can do that directly. Perhaps you can ask for both the object ID and the flight code, group by flight code, and take the minimum object ID, to get one object ID for each flight code. Then you can turn those object IDs into full objects one by one using objectForID: on the managed object context. I would try something like this:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Flight"
    inManagedObjectContext:moc];

NSExpressionDescription *objectIDProperty = [[NSExpressionDescription alloc] init];
objectIDProperty.name = @"objectID";
objectIDProperty.expression = [NSExpression expressionForFunction:@"min:"
    arguments:@[ [NSExpression expressedForEvaluatedObject] ]];
objectIdProperty.expressionResultType = NSObjectIDAttributeType;

NSAttributeDescription *flightCodeProperty = entity.propertiesByName[@"flightCode"];
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entity.name];
request.resultType = NSDictionaryResultType;
request.returnsDistinctResults = YES;
request.propertiesToFetch = @[ flightCodeProperty, objectIDProperty ];

request.propertiesToGroupBy = @[ flightCodeProperty ];

I cribbed a lot of that from this answer. I have no idea if it works, or if I'm even on the right track. If it runs at all, but doesn't quite give the right output, remember that you can see the SQL it's executing by adding -com.apple.CoreData.SQLDebug 1 as a command-line argument.

Upvotes: 1

Ben
Ben

Reputation: 607

youll want to make a NSMuteableArray for all of your flights and then a separate NSMuteableArray to keep track of which elements you have already seen

pseudocode:

NSMuteablearray flights
NSMuteablearray alreadySeen


for (item in flights) {
if (alreadySeen containsObject:item)
     flights removeObject:item
else
     alreadySeen addObject:item

}

Upvotes: 0

Related Questions