iPhone - Sorting NSArray based on available data in dictionary - iphone

I'm having NSDictinary objects array.
Each dictionary object has keys "display_name", "first_name" and "last_name".
Some dict objects have only display_name and some will not have.
Some dict objects have only first_name and some will not have.
Some dict objects have only last_name and some will not have.
I'm using this array to show the list in table view. What I am looking for is to sort the dict with following preference:
1. If display name is available, use that.
2. If display name is not available and first name is available, use that.
3. else last name.
How can I sort the array using above preference. I want to use NSPredicate the app has to work on older iOS as well....
I tried different combinations of NSPredicate as following, but I didn't succeeed:
NSSortDescriptor* firstNameDescriptor;
NSSortDescriptor* lastNameDescriptor;
NSSortDescriptor* displayNameDescriptor;
displayNameDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"display_name" ascending:YES];
lastNameDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"last_name" ascending:YES];
firstNameDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"first_name" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:firstNameDescriptor, lastNameDescriptor,nil];
self.contactsArray = (NSMutableArray*)[tempArray sortedArrayUsingDescriptors:sortDescriptors];
Can some one guide me in right way to achieve it?

you can use :
sortedArrayUsingFunction:context:
and implement the rules you just listed in your own custom sorting function

What I did is that during sorting, I added another key to the dictionary "final_name" and the value is set according to my preference of names to display and just sorted the array with "final_name".
NSArray* tempArray = [jsonData objectForKey:#"contacts"];
for (NSDictionary* conDict in tempArray)
{
NSString* fName = [conDict objectForKey:#"first_name"];
NSString* lName = [conDict objectForKey:#"last_name"];
NSString* dName = [conDict objectForKey:#"display_name"];
NSString* finalName = #"<<No Name>>";
if (dName && ![dName isEqual:[NSNull null]]) {
finalName = dName;
}
else if (fName && ![fName isEqual:[NSNull null]] && lName && ![lName isEqual:[NSNull null]])
{
finalName = [NSString stringWithFormat:#"%# %#",fName,lName];
}
else if (fName && ![fName isEqual:[NSNull null]])
{
finalName = fName;
}
else if (lName && ![lName isEqual:[NSNull null]]) {
finalName = lName;
}
[conDict setValue:finalName forKey:#"final_name"];
}
if ([tempArray count])
{
NSSortDescriptor* finalSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"final_name" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:finalSortDescriptor,nil];
self.contactsArray = [[NSArray alloc] initWithArray:[tempArray sortedArrayUsingDescriptors:sortDescriptors]];
}

Related

Sort NSArray with multiple NSDictonaries in it [duplicate]

This question already has answers here:
Sorting NSArray of dictionaries by value of a key in the dictionaries
(11 answers)
Closed 9 years ago.
I need to sort the given "document" array with "lastname". Here is the sample json
document [
{
id:"100"
person :{
name : {
firstname : "xyz",
lastname : "oops"
},
photourl: "photo-url"
}
},
{
id:"200"
person :{
name : {
firstname : "xyz",
lastname : "oops"
},
photourl: "photo-url"
}
}]
it has an dict "name" inside one more dict "person" and we need to sort with lastname first n then with lastname
NSSortDescriptor *lastNameDescriptor = [[NSSortDescriptor alloc] initWithKey:#"lastname " ascending:YES] ;
NSArray *sortedArray = [NSArray arrayWithObject:lastNameDescriptor];
sortedArray = [myArray sortedArrayUsingDescriptors:sortDescriptors];
for more clear description and code check this link, its very easy and perfect, Cheers :)
Use the below given logic
for (NSMutableDictionary *document in documents) {
NSString *lastName = [[document valueForKey:#"person"] valueForKey:#"lastname"];
[documents setObject:lastName forKey:#"lastnameDescriptor"];
}
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"lastnameDescriptor" ascending:YES];
NSMutableArray *sortedNames = [documents sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]];
for (NSMutableDictionary *document in sortedNames) {
[document removeObjectForKey:#"lastnameDescriptor"];
}
The other answers are close but either needlessly complicated or a little off.
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"person.lastName" ascending:YES];
sortedArray = [document sortedArrayUSingDescriptors:#[descriptor]];
(The selector says "key," but if you read the docs, it's actually a keypath, so this will work as expected.)
Lots of almost right answers but none that consider that 'name' is itself a nested dictionary in your document. So I think what you want is:
NSSortDescriptor *lastNameDescriptor = [NSSortDescriptor sortDescriptorWithkey:#"person.name.lastname" ascending:YES];
NSSortDescriptor *firstNameDescriptor = [NSSorteDescriptor sortDescriptorWithKey:#"person.name.firstname" ascending:YES];
NSArray *sortedArray = [document sortedArrayUsingDescriptors:#[lastNameDescriptor, firstNameDescriptor]];
So assuming you put your JSON into an array called "people":
NSArray *people = myArrayFromJSON;
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"person" ascending:YES comparator:^NSComparisonResult(id obj1, id obj2) {
NSString *lastName1 = [obj1 valueForKey:#"lastname"];
NSString *lastname2 = [obj2 valueForKey:#"lastname"];
return [lastName1 compare:lastname2];
}];
NSArray *sortedArray = [people sortedArrayUsingDescriptors:#[sortDescriptor]];
That'll do it.

Objective C: Filter out results from NSMutableArray by a dictionary key's value?

I have a NSMutableArray like this :
(
{
City = "Orlando";
Name = "Shoreline Dental";
State = Florida;
},
{
City = "Alabaster ";
Name = Oxford Multispeciality;
State = Alabama;
},
{
City = Dallas;
Name = "Williams Spa";
State = Texas;
},
{
City = "Orlando ";
Name = "Roast Street";
State = Florida;
}
)
Now how can I sort this NSMutableArray to get the results corresponding to State "Florida"
I expect to get
(
{
City = "Orlando";
Name = "Shoreline Dental";
State = Florida;
},
{
City = "Orlando ";
Name = "Roast Street";
State = Florida;
}
)
I went for this code,but it displays again the prevous four dictionaries .
NSSortDescriptor *valueDescriptor = [[NSSortDescriptor alloc] initWithKey:#"Florida" ascending:YES];
NSArray * descriptors = [NSArray arrayWithObject:valueDescriptor];
NSArray * sortedArray = [arr sortedArrayUsingDescriptors:descriptors];
Try using a comparator block:
NSIndexSet *indices = [array indexesOfObjectsPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
return [[obj objectForKey:#"State"] isEqualToString:#"Florida"];
}];
NSArray *filtered = [array objectsAtIndexes:indices];
Alternatively, you can use a predicate as well:
NSPredicate *p = [NSPredicate predicateWithFormat:#"State = %#", #"Florida"];
NSArray *filtered = [array filteredArrayUsingPredicate:p];
If your array contains dictionary then you can use NSPredicate to filter out your array as follows:
NSPredicate *thePredicate = [NSPredicate predicateWithFormat:#"State CONTAINS[cd] Florida"];
theFilteredArray = [theArray filteredArrayUsingPredicate:thePredicate];
Assuming your array name is : arr
This one of the typical way to find, although a bit obsolete way....
for (NSDictionary *dict in arr) {
if ([[dict objectForKey:#"State"]isEqualToString:#"Florida"]) {
[filteredArray addObject:dict];
}
}
NSLog(#"filteredArray->%#",filteredArray);
Using predicates and blocks are already posted :)
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"State = %#", #"Florida"];
NSArray *filteredArray = [arr filteredArrayUsingPredicate:predicate];
NSLog(#"filtered ->%#",filteredArray);

Sort array of dictionary objects

the problem im having is that i cant sort an NSMutableArray of NSMutableDictionary Objects, I want to sort the objects by rating, the rating is a NSNumber, what am i missing?
My current code that sums all the ratings from "arrayMealRating" and sorts the resulting array:
[arrayMealRating addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:
[eachObject objectForKey:#"Airline"], #"Airline"
,[eachObject objectForKey:#"setMealRating"], #"setMealRating"
, nil]];
}
NSArray *airlineNames = [arrayMealRating valueForKeyPath:#"#distinctUnionOfObjects.Airline"];
// Loop through all the airlines
for (NSString *airline in airlineNames) {
// Get an array of all the dictionaries for the current airline
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(Airline == %#)", airline];
NSArray *airlineMealRating = [arrayMealRating filteredArrayUsingPredicate:predicate];
// Get the sum of all the ratings using KVC #sum collection operator
NSNumber *rating = [airlineMealRating valueForKeyPath:#"#sum.setMealRating"];
//NSLog(#"%#: %#", airline, rating);
[sortedMealArray addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:
airline, #"Airline"
,[rating stringValue], #"setMealRating"
, nil]];
}
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"setMealRating" ascending:YES];
[sortedMealArray sortedArrayUsingDescriptors:[NSMutableArray arrayWithObjects:descriptor,nil]];
auxMealRating = [sortedMealArray copy];
Any doubt, please dont down vote, just ask and i will edit the question.
Best Regards and sorry for my poor english.
This should do what you want:
NSArray *sortedArray = [arrayMealRating sortedArrayUsingComparator:^(id obj1, id obj2) {
NSNumber *rating1 = [(NSDictionary *)obj1 objectForKey:#"setMealRating"];
NSNumber *rating2 = [(NSDictionary *)obj2 objectForKey:#"setMealRating"];
return [rating1 compare:rating2];
}];

Filtering NSArray/NSDictionary using NSPredicate

I've been trying to filter this array (which is full of NSDictionaries) using NSPredicate...
I have a very small amount of code that just isn't working...
The following code should change label.text to AmyBurnett34, but it doesn't...
NSPredicate *pred = [NSPredicate predicateWithFormat:#"id = %#", [[mightyPlistDict objectForKey:#"pushesArr"] objectAtIndex:indexPath.row]];
NSLog(#"%#",pred);
label.text = [[[twitterInfo filteredArrayUsingPredicate:pred] lastObject] objectForKey:#"screen_name"];
NSLog(#"%#",twitterInfo);
And here is what gets NSLoged...
2012-08-05 11:39:45.929 VideoPush[1711:707] id == "101323790"
2012-08-05 11:39:45.931 VideoPush[1711:707] (
{
id = 101323790;
"screen_name" = AmyBurnett34;
},
{
id = 25073877;
"screen_name" = realDonaldTrump;
},
{
id = 159462573;
"screen_name" = ecomagination;
},
{
id = 285234969;
"screen_name" = "UCB_Properties";
},
{
id = 14315150;
"screen_name" = MichaelHyatt;
}
)
Just for the heads up if you also NSLog this... the array is empty...
NSLog(%#,[twitterInfo filteredArrayUsingPredicate:pred]);
The problem is that your predicate is using comparing with a string and your content is using a number. Try this:
NSNumber *idNumber = [NSNumber numberWithLongLong:[[[mightyPlistDict objectForKey:#"pushesArr"] objectAtIndex:indexPath.row] longLongValue]];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"id = %#", idNumber];
You don't know for sure that the value of "id" is a string - it might be a NSNumber. I suggest:
NSUInteger matchIdx = ...;
NSUInteger idx = [array indexOfObjectPassingTest:^BOOL(NSDictionary *dict, NSUInteger idx, BOOL *stop)
{
id obj = [dict objectForKey:#"id"];
// NSLog the class if curious using NSStringFromClass[obj class];
NSUInteger testIdx = [obj integerValue]; // works on strings and numbers
return testIdx == matchIdx;
}
if(idx == NSNotFound) // handle error
NSString *screenName = [[array objectAtIndex:idx] objectForKey:#"screen_name"];
NSPredicate is used for filtering arrays, not sorting them.
To sort an array, use the sortedArrayUsingDescriptors method of NSArray.
An an example:
// Define a sort descriptor based on last name.
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"lastName" ascending:YES];
// Sort our array with the descriptor.
NSArray *sortedArray = [originalArray sortedArrayUsingDescriptors:[NSArray arrayWithObjects:descriptor, nil]];

Sorting ABRecords alphabetically on iPhone

I'm retrieving contact names with this code:
for( int i = 0 ; i < n ; i++ )
{
Contact *c = [[Contact alloc] init];
ABRecordRef ref = CFArrayGetValueAtIndex(all, i);
NSString *firstName = (NSString *)ABRecordCopyValue(ref, kABPersonFirstNameProperty);
NSString *lastName = (NSString *)ABRecordCopyValue(ref, kABPersonLastNameProperty);
c.firstName = firstName; //[NSString stringWithFormat:#"%# %#", firstName, lastName];
c.lastName = lastName;
[contacts addObject:c];
[c release];
}
Does anyone know a way of ordering this list alphabetically? I've read about sortedArrayUsingSelector:#selector(compare:) but I have no idea how that is supposed to work.
NSSortDescriptor *mySorter = [[NSSortDescriptor alloc] initWithKey:#"lastName" ascending:YES];
[contacts sortUsingDescriptors:[NSArray arrayWithObject:mySorter]];
[mySorter release];
This method will let you respect the user's preferences for sorting by first or last name.
contacts = (bridgedPeople as [ABRecord]).sort {
(person1, person2) -> Bool in
return .CompareLessThan == ABPersonComparePeopleByName(person1, person2, ABPersonGetSortOrdering())
}
Pro-tip: Boldface the part of the name that you're sorting on; otherwise it gets confusing when you mix contacts who have [no first name, no last name, first and last name]