iOS Sorting by Parse relation size - ios

I have some User objects on my Parse backend with a relation with "Comment" objects. I want to query and sort by the users with the highest number of objects in the previous relation, however I am not sure how to go about doing this.
Any tips?
Thanks

I assume after parsing your response you are left with an array of objects with a property comments which is again an array of objects, something like this:
// NSLog(#"%#", users);
(
{
comments = (
{
date = "2016-01-13T02:04:52+00:00";
content = "nice comment, bro";
}
);
userName = "louise.lausebär";
}
)
Sorting that by count of comments is super simple with NSSortDescriptor and KVO Collection Operators:
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"comments.#count" ascending:YES];
[array sortUsingDescriptors:#[descriptor]];

Related

iOS objective C: custom sorting NSarray not default ascending/descending

I have a question regarding custom sorting of nsarray. I currently have an nasty sorted by a key(commandeState) that can take 3 values( 5,6,7). so far I can sort it ascending/descening like this:
NSSortDescriptor *descr = [NSsortDescriptor] sortDescriptorwithKey: #"commandesState" ascending:NO];
What I want to achieve is having the nsarray sorted in this order 6,5,7. Can anyone help showing how I could achieve this?
Thank you in advance.
Iterate the for loop and manage or order object accordingly.
Create another dictionary with 5,6,7 as keys and value contains the array of object where key commandeState is the dictionary key.
Then from above dictionary create an array by appending elements.
You can use
NSArray *sortedArray;
sortedArray = [notSortedArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
if (a.value == 6) {
return true;
} else if (b.value == 6) {
return false;
} else {
return a.value > return b.value;
}
}];
Bassically is a normal asc sort, but with a rule over the "6 value".

iOS, Sort allKeys of NSDictionary

<-- Why have i been down voted? At least comment some reasoning
I have an incoming JSON array which details consecutive & non-consecutive date periods.
An example:
(Please note, the root index values are for example clarity. The real data is just associative key-value)
[0] => '01/01/2015 - 05/01/2015' : ['01/01/2015',
'02/01/2015',
'03/01/2015',
'04/01/2015',
'05/01/2015'],
[1] => '01/02/2015 - 05/02/2015' : ['01/02/2015',
'02/02/2015',
'03/02/2015',
'04/02/2015',
'05/02/2015'],
[2] => '25/03/2015': '25/03/2015',
[3] => '01/04/2015': '01/04/2015'
My final intention is to display each associative key in a UITableView, where consecutive date cells (indexes [0] & [1] in the example), on select will segue to another UITableView listing each individual date of the consecutive block. Non-consecutive date cells, (index [2] & [3] in example) will not be selectable to the user as there is nothing more to see. savvy?
My issue is that i import the JSON array into both an NSArray, & NSDictionary. (The reader should be aware that arrays are ordered, where as dictionaries are not)
NSArray of the imported data is structured true. The issue is i have no way of displaying the keys in the first UITableView, from which the 2nd UITableView can be populated with the relating value.
I take an NSArray of allKeys of the NSDictionary, which gives me the structured array of the keys of the un-structured dictionary. This i can use to display in the first UITableView, however its representation of data structure is not true to the imported structure. Its all jumbled & different each time.
My question is how the hell do i do this? but i should imagine that question may not be specific enough.... so, How would i sort the allKeys array of the dictionary in date order?
If your thinking, "Well this is easy! just sort using a descriptor",
like this one...?
NSSortDescriptor *descriptor=[[NSSortDescriptor alloc] initWithKey:#"self" ascending:NO];
NSArray *descriptors=[NSArray arrayWithObject: descriptor];
NSArray *reverseOrder=[self.dateKeys sortedArrayUsingDescriptors:descriptors];
Sadly, that would be too easy. That works fine with non-consecutive date keys, or single dates, but where i have consecutive date keys, '01/01/2015 - 05/01/2015' it fails. The overall NSArray is closer to the true imported data structure, but not close enough
You could map the response into an NSArray, where each item is an NSDictionary with a key (the range) and either an NSArray of values (the dates) or an NSString (single date).
Example:
NSArray *data = #[
#{
#"01/01/2015 - 05/01/2015" : #[
#"01/01/2015",
#"02/01/2015",
#"03/01/2015",
#"04/01/2015",
#"05/01/2015"
]
},
#{
#"25/03/2015" : #"25/03/2015"
}
];
Then, you can fill the first UITableView from the the main array, so from each item in the array, you get the dictionary key.
NSMutableArray *table1Data = [[NSMutableArray alloc] initWithCapacity:data.count];
for (NSDictionary *dateRange in data) {
[table1Data addObject:[[dateRange allKeys] firstObject]];
}
And the second UITableView is filled from the value of the dictionary (array of dates) of the selected item in the main array, only when the value is an NSArray:
id table2Data = [[data[selectedIndex] allValues] firstObject];
if ([table2Data isKindOfClass:[NSArray class]]) {
// Navigate to second view, passing table2Data as the second table view data.
// Cast table2Data to an NSArray if needed.
}
else {
// Do not navigate to the second view
}
If I read you correctly, you want to show one TableView with the date ranges (keys) in chronological order as follows:
Row 1: 01/01/2015 - 05/01/2015
Row 2: 01/02/2015 - 05/02/2015
Row 3: 25/03/2015
Row 4: 01/04/2015
And then, when tapping into row 1 or 2, show all the dates in the range in another TableView, i.e. for Row 1:
Row 1: 01/01/2015
Row 2: 02/01/2015
Row 3: 03/01/2015
Row 4: 04/01/2015
Row 5: 05/01/2015
You do need to store this data in an NSDictionary *dateRanges but as you are dealing with strings you need to encapsulate these date ranges in new classes which will make it easier to sort their values.
For instance, you may have a DateRange class with two #properties of type NSDate: startDate and endDate, where endDate is nil for those single dates (i.e. 25/03/2015) . You can then use an NSSortDescriptor to sort by startDate for the [dateRanges allKeys]:
NSArray *dateKeys = [self.dateRanges allKeys];
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"startDate" ascending:NO];
NSArray *reverseOrder = [dateKeys sortedArrayUsingDescriptors:#[ descriptor ]];

NSFetchedResultController complex sort case

I have following data model:
[Agency] <--->> [AgencyRating] <<---> [RatingType]
There are numbers of rating types (ex. overall, branding, design, programming, etc). Each agency can have all these rating types (ex. agency FooBar has 1050 points in design and 700 points in branding).
Tables structures:
Agency: name:string
RatingType: name:string
AgencyRating: agency_ref: relationship to agency, ratingType_ref: relationship to rating type, value: Integer.
I have split view controller. Left side contains available rating types. When user picks any rating type, I'd like to show sorted by rating value agencies on the right side.
I'd like to achieve it with NSFetchedResultController. I understand how to get rating values to display it in cells, but I don't understand how to make a sort descriptor.
Currently I have:
Controller:
_contentFetchController = [Agency MR_fetchAllGroupedBy:nil withPredicate:[NSPredicate predicateWithValue:YES] sortedBy:#"name" ascending:YES];
Cell:
- (void) configureForAgency:(Agency *) agency ratingType:(RatingType *) ratingType forIndexPath:(NSIndexPath *) path {
self.positionLabel.text = [NSString stringWithFormat: #"%d", (int)path.row + 1];
UIImage *image = [UIImage imageWithContentsOfFile:agency.logoPath];
if (image) {
self.logoImageView.image = image;
}
self.nameLabel.text = agency.name;
// HERE IS VALUE OF RATING
self.ratingValueLabel.text = [[agency ratingForRatingType:ratingType] stringValue];
}
As you can see: I sort by name, but I need to sort by rating value, based on selected rating type. Any ideas?
In order to do that you need to fetch Agencies, that have an associated AgencyRating with a selected rating type and sort everything by rating value.
I assume that rating type is ratingType, rating value is ratingValue and AgencyRating association is agencyRatings. I also assume that each agency can have only one agency rating of each rating type (if not, you will have to sort by the SUM of all agency ratings of selected type).
Judging by the MR_ prefix, I guess you are using MagicalRecord, which I'm not familiar with, but here's how you can do that with plain NSFetchRequest and NSFetchedResultsController.
First you will need to set up a NSFetchRequest:
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Agency"];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"ANY agencyRatings.ratingType = %#", ratingType];
fetchRequest.sortDescriptors = #[ [NSSortDescriptor sortDescriptorWithKey:#"agencyRatings.ratingValue" ascending:YES] ];
Then you can set up the NSFetchedResultsController as you would normally do providing it with the fetchRequest you just created.
Every time the user changes the ratingType you will need to change the fetchRequest's predicate and call performFetch on the fetchedResultsController.
I guess you need to adjust this a little bit to fit your case, but the idea is to to have a predicate and a sort descriptor that are pointing to a related table.

Sort NSarray based on integer value stored in the array of objects

I have Nssarray named Cameralist; in that I have collection of camerainfo class objects.
[ cameraInfoObject1 , cameraInfoObject2, cameraInfoObject3 , ...etc]
There is one property for each camerInfo object i.e cameraindex which is integer.
Therefore it is cameraInfoObject1.Cameraindex.
Hence I want to sort my cameralist array based on the camera index which is property present in every cameraInfoObject inside cameralist object.
Currently I am using this
NSSortDescriptor* sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"camerainfo.cameraindex" ascending:YES selector:#selector(intValue)];
[self.service.gMyCameraList sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
but my app crashes as soon as the control reaches this point.
Try something like this:
NSArray *sortedArray;
sortedArray = [self.service.gMyCameraList sortedArrayUsingComparator:^NSComparisonResult(CameraInfo a, CameraInfo b) {
if ( a.Cameraindex < b.Cameraindex) {
return (NSComparisonResult)NSOrderedAscending;
} else if ( a.Cameraindex > b.Cameraindex) {
return (NSComparisonResult)NSOrderedDescending;
}
return (NSComparisonResult)NSOrderedSame;
}];
Assuming that your objects are CameraInfo type, if not, just change that name.

How to use Core Data relationship?

In my app I have 3 related entities. Athlete, Exercise, and Exercise Score.
Athlete has a to-many relationship with Exercise. It's inverse is whosExercise.
Exercise has a to-many relationship with exercise score. It's inverse is whichExercise.
I want to perform a fetch request where I get all the exercise scores for an athlete. How would I get that? Do I need another relationship between Athlete and Exercise Scores, or is that redundant? If it is, how would I use exercise as a predicate for my request?
If Exercise has a relationship to Athlete, then you should be able to do something like:
[NSPredicate predicateWithFormat:#"SELF.athlete = #%", currentAthlete];
and then just:
[Exercise fetchByPredicate:currentAthletePredicate];
Should be it.
If I clearly understand, you need to select all ExerciseScore for Athlete, but Athlete does not have direct relationship with ExerciseScore table.
SLQ Query for this may looks like :
Select *
from ExerciseScore
where IDScore in (select IDScore
from Exercise
where IDExercise in ( select IDExercise
from Athlete
)
)
But in Core Data you can't operate SLQ Queries.
Try this approach.
1.Fetch all Exercise for Athlete:
NSError *error;
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Exercise"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.athlete = #%", currentAthlete];
request.predicate=predicate;
NSArray *athleteExercises = [self.managedObjectContext executeFetchRequest:request error:&error];
2.Iterate throughout array of Exercises to get all Exercise score for each Exercise.
NSMutableArray *allScores = [NSMutableArray arrayWithCapacity:0];;
for (Exercise *exercise in athleteExercises) {
if ([exercise.scores count]>0) {
[allScores addObjectsFromArray:[exercise.scores allObjects]; //exercise.scores must be NSSet type
}
}
allScores array now contain All ExerciseScore objects for particular Athlete.
Predicates can have key paths:
#"whichExercise.whosExercise = %#",athlete
Or, if you have the athlete already, don't do a fetch request, just get the scores via the relationship properties.

Resources