3

I tried to build a predicate in a previous post, but ended up doing it this way because after 3 hours, I couldn't get it to work.

I feel like there has to be a more effective way, also I need the predicates to be case insensitive.

10,000 cars I have a tire, wheel, seat as three car parts I want to find all cars that have a tire. THEN I want to find all cars that have a wheel. THEN I want to find all cars that have a seat. (I know many will be duplicates, but that's what I need)

Please let me know if there is a more effective way. Also please let me know how to make the predicates case insensitive.

Thank you in advance!

-(NSArray*) loadCarsFromCoreData:(NSMutableArray*)inputCarParts{

    NSMutableArray *totalResults=[[NSMutableArray alloc]init];
    NSFetchRequest *fetchRequest =[[NSFetchRequest alloc]init];

    //To find the cars we are using the car parts
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"CarParts" inManagedObjectContext:[self managedObjectContext]];
    [fetchRequest setEntity:entity];
    NSError *error;
    NSMutableArray *predicates =[self parseCarPartsIntoAPredicateArray:inputCarParts];
    for (int i=0; i<[predicates count]; i++) {
        [fetchRequest setPredicate:[predicates objectAtIndex:i]];

        NSArray *records = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
        NSLog(@"results = %i",[records count]);
        [totalResults addObjectsFromArray:records];
    }
    NSLog(@"results = %i",[totalResults count]);
    return [NSArray arrayWithArray:totalResults];
}

-(NSMutableArray*)parseCarPartsIntoAPredicateArray:(NSMutableArray*)inputCarParts{
    NSMutableArray *returnArray=[[NSMutableArray alloc]init];
    for (int i=0; i<[inputCarParts count]; i++) {
        NSPredicate *predicate=[NSPredicate predicateWithFormat:@"partName == %@",[inputCarParts objectAtIndex:i]];
        [returnArray addObject:predicate];
    }

    return returnArray;
}
William Falcon
  • 9,813
  • 14
  • 67
  • 110
  • "I know many will be duplicates, but that's what I need". So, you want your results to have more than one entry for the same object? That is, if it has both a tire and a wheel, you want it to show up twice? – Tom Harrington Jan 02 '13 at 18:05
  • Car a = wheel, seat. ||Car b = wheel. ||Car c = seat. ||Car d = wheel,seat,tire. ||Car e = trunk. ||I need a,b,c,d. – William Falcon Jan 02 '13 at 18:34

2 Answers2

11

It sounds like what you're really looking for is how to construct a predicate based on an array of possible matches. In that case you'd do something like this:

NSMutableArray *partPredicates = [NSMutableArray arrayWithCapacity:[inputCarParts count]];
for (NSString *partName in inputCarParts) {
    NSPredicate *currentPartPredicate = [NSPredicate predicateWithFormat:@"partName =[c] %@", partName];
    [partPredicates addObject:currentPartPredicate];
}
NSPredicate *fullPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:partPredicates];

The resulting predicate would then be something like partName ==[c] "tire" OR partName ==[c] "wheel" OR partName ==[c] "seat", with one component per array entry. Do one fetch to evaluate them all in one shot.

This will not get duplicate results if you use it in the fetch. You left a comment on the question that indicates you don't want duplicates. If that's the case though, then I'm not sure what I know many will be duplicates, but that's what I need means. It sounds like you wanted the dupes, but you said you didn't.

Tom Harrington
  • 69,312
  • 10
  • 146
  • 170
  • just beat me to it. Ended up doing it exactly this way. I hate wasting 8 hours on something it takes others 10 minutes... Thanks – William Falcon Jan 02 '13 at 18:50
  • does it make sense what I'm doing by searching backwards (part -> car), or should I load all cars, and then nspredicate that array for my matches? – William Falcon Jan 02 '13 at 18:51
  • When you say "load all cars", where would you be loading them from? Do you use Core Data? – Bio Jan 02 '13 at 18:55
  • yes core data (do a query for entity Cars, with no filters). cars has a to many with parts and parts to many with cars – William Falcon Jan 02 '13 at 18:58
  • Loading out all the Car objects from Core Data into an array would just create unnecessary overhead. Just access the Car objects you need from Core Data using your predicates. – Bio Jan 02 '13 at 19:02
  • Yeah, fetch the objects you need. Don't load every object of a type unless you actually need all of them. – Tom Harrington Jan 02 '13 at 19:08
  • so keep it how it is, or change to searching cars, with predicates for the parts (sorry first week using core data). also please see this (i think I'm loading them wrong) http://stackoverflow.com/questions/14127690/issue-loading-subentities-to-mangedobject-in-coredata – William Falcon Jan 02 '13 at 19:10
  • Hi, so I am actually getting duplicates here. Any thoughts? I didn't mind them in the initial post, but if I can avoid it then better – William Falcon Jan 02 '13 at 20:40
  • You shouldn't be getting duplicate managed objects, but there's no automatic check that prevents more than one managed object with identical attributes. Is there any chance that's what's happening? – Tom Harrington Jan 02 '13 at 22:31
3

If you need the duplicates, I think you'll have to do 3 separate queries like you're currently doing.

If the duplicates aren't important, you should try creating a compound predicate by using OR between the three predicates you need. The following will find all the cars that either have the specified wheel, tire, or seat:

NSPredicate *predicate=[NSPredicate predicateWithFormat:@"wheelPartName == %@ OR tirePartName == %@ OR seatPartName == %@", wheelPart, tirePart, seatPart];

To make your searches case insensitive, use ==[c] instead of ==, so the predicate in your code would look like:

NSPredicate *predicate=[NSPredicate predicateWithFormat:@"partName ==[c] %@",[inputCarParts objectAtIndex:i]];

Take a look at this reference: String Predicate Programming.

Bio
  • 505
  • 4
  • 10
  • How do I make this using an array, it didn't work for me earlier "NSPredicate *predicate=[NSPredicate predicateWithFormat:@"wheelPartName == %@ OR tirePartName == %@ OR seatPartName == %@", wheelPart, tirePart, seatPart];" – William Falcon Jan 02 '13 at 18:28