1

I am used to working in C# using the linq extensions (list.select(...).where(...) ext), and I was wondering if there was some way of doing the same sort of thing in Objective-C. This would save me from building a number of rather complicated queries using Core Data, which is great for some things, but perhaps not the best for complex queries (or maybe I'm just uninformed).

Is there some kind of equivalent for linq in Objective-C/Core Data?

EDIT: More specifically, I would like to count the number of elements that fit some criteria. Say my model has a field called date. I am trying to select the distinct dates, and then calculate how many of each date there are. In SQL this would be like a group by, and a COUNT aggregate.

mtmurdock
  • 12,756
  • 21
  • 65
  • 108
  • Rather than tacking on an "EDIT:", you should just rewrite your question to be more specific. – benzado Feb 10 '12 at 06:51
  • I understand what you're saying, but I had already received some answers and I wanted it to be clear to those following that the question body had changed. – mtmurdock Feb 10 '12 at 17:21

5 Answers5

1

Your question goes from very general ("linq equivalent?") to very specific (computing count by date). I'll just answer your specific question.

Unfortunately, NSArray doesn't have a built-in map or select method, but it does offer NSCountedSet, which will compute what you want:

NSCountedSet *dateSet = [NSCountedSet set];
for (id thing in array) {
    [dateSet addObject:[thing date]];
}
for (NSDate *date in dateSet) {
    NSLog(@"There are %d instances of date %@", [dateSet countForObject:date], date);
}
benzado
  • 82,288
  • 22
  • 110
  • 138
  • This looks very promising. I'll give it a try. Is `uniqueDates` supposed to be `dateSet` in your example? – mtmurdock Feb 10 '12 at 17:20
  • Yours was the most simple and elegant (though I'm sure others would work). Well done. Thanks! – mtmurdock Feb 11 '12 at 03:37
  • `uniqueDates` was supposed to be `dateSet`; I must have decided to change the name while writing the code. Glad you figured it out anyway. – benzado Feb 11 '12 at 18:26
1

Change predicate , and "Date" keys with your props

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"child" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setReturnsDistinctResults:YES];
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObject:@"Date"]];
NSPredicate *predicate =[NSPredicate predicateWithFormat:@"(start <= %@ ) and (completion < 100)",sda ];
[fetchRequest setPredicate:predicate];
int c = [self.managedObjectContext countForFetchRequest:fetchRequest error:nil];
Sanjeev Rao
  • 2,247
  • 1
  • 19
  • 18
  • Ok this is looking better. So I would have to call `countForFetchRequest:error:` for every distinct date then? Still not ideal... Could this be changed to pull back a list of key-value pairs, where Date is the key and count is the value? – mtmurdock Feb 10 '12 at 17:17
0

Here was something posted with comes close filtering NSArray into a new NSArray in objective-c

Anyway AFAIK you don't have some sort of linq in Objective-C but you have. Arrays and Blocks. And Blocks are functions. So you can really filter on anything in there.

Community
  • 1
  • 1
Friedrich
  • 5,916
  • 25
  • 45
0

Of course, Cora Data has many functions to make complex queries: In example to get sum of elements, you have two major ways:

first - get your data to NSSet or NSArray and use @sum operator:

//assume that `childs` are NSArray of your child entities and ammount is attribute to sum, and has attributes start (date) and completion (integer)

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"child" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];

NSPredicate *predicate =[NSPredicate predicateWithFormat:@"(start <= %@ ) and (completion < 100)", dzis];
[fetchRequest setPredicate:predicate];

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"];
NSError *error = nil;
if ([afetchedResultsController performFetch:&error]) {
    NSArray *childs = afetchedResultsController.fetchedObjects;
    NSNumber *sum=[childs valueForKeyPath:"@sum.ammount"];
}

second is using specific fetch for specific value with added NSExpressionDescription with a sum. This way is harder but better for larger db's

Tomasz Wojtkowiak
  • 4,910
  • 1
  • 28
  • 35
0

suppose if you have an array of your model objects, you could that with the following statement,

NSArray *distintDatesArray = [array valueForKeyPath:@"@distinctUnionOfObjects.date"];

    for ( NSDate *date in distintDatesArray)
    {
        NSLog (@"Date :%@ ,count : %d",date,[[array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"date = %@",date]] count]);
    }

This will have same effect as the group by query.

Vignesh
  • 10,205
  • 2
  • 35
  • 73
  • I don't need the number of distinct dates, I need count of EACH distinct date. I want to know how many entries have the same date, for all distinct dates. – mtmurdock Feb 10 '12 at 17:18