Sorting an NSArray in reverse order - objective-c

NSArray* sortedArray = [myArray sortedArrayUsingSelector:#selector(compare:)];
Just wondering how I can sort this array of numbers in descending order?

Either use the method that allows you to pass a block as a comparator and implement a comparator that reverses the objects (returns NSOrderedAscending for NSOrderedDescending and vice versa)....
... or:
NSArray *reversed = [[[myArray sortedArrayUsingSelector:#selector(compare:)] reverseObjectEnumerator] allObjects];
Sorry. Derped the most important part.

Use NSSortDescriptor
NSSortDescriptor* sortOrder = [NSSortDescriptor sortDescriptorWithKey: #"self" ascending: NO];
NSArray *temp = [myArray sortedArrayUsingDescriptors: [NSArray arrayWithObject: sortOrder]];

I like to use the sortedArrayUsingFunction: method which gives full control of how the array is sorted. Then to reverse the results return the negative value of what you would have returned.
NSInteger myCompare (id obj1, id obj2, void *context) {
int retval = [obj1 compare:obj2 options:NSNumericSearch];
retval = -retval; // now it's sorted reverse
return retval;
}
...
NSArray *arr = #[#"foo20zz", #"foo7zz", #"foo100zz"];
NSArray *sarr = [arr sortedArrayUsingFunction:myCompare context:NULL];
NSLog(#"sarr is %#", sarr);

Related

sort a dictionary by a key from an inner dictionary

i have a dictionary which i want to sort it according to a key from an inner dictionary. Each key in the super dictionary has a dictionary as value. As an example to illustrate what i'm talking about, here is a super dictionary with inner dictionaries respectively to each key.
{
key1 = {count = 2},
key2 = {count = 1}
}
thus the count key has to be the key used for the sorting. For now i know only how to sort arrays and i didn't encounter sorting dictionaries before. Any help will be appreciated.
get the array out of dictionary & sort it
NSArray* values = [myDict allValues];
NSArray* sortedValues = [values sortedArrayUsingSelector:#selector(comparator)];
another way to do it to make NSSortDescriptor
keyDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"count" ascending:YES] autorelease];
sortDescriptors = [NSArray arrayWithObject:keyDescriptor];
sortedArray = [myArray sortedArrayUsingDescriptors:sortDescriptors];
I pulled the code from Sort Descriptor Programming Topics. Also, Key-Value Coding comes into play, in that sortedArrayUsingDescriptors: will send a valueForKey: to each element in myArray, and then use standard comparators to sort the returned values.
Here's one way:
NSDictionary * dict1 = [[NSDictionary alloc]initWithObjectsAndKeys:[NSNumber numberWithInt:2], #"count", nil];
NSDictionary * dict2 = [[NSDictionary alloc]initWithObjectsAndKeys:[NSNumber numberWithInt:3], #"count", nil];
NSArray * arrayOfDictionaries = [[NSArray alloc]initWithObjects:dict1, dict2, nil];
NSArray * sortedArray = [arrayOfDictionaries sortedArrayUsingComparator:^NSComparisonResult(NSDictionary * obj1, NSDictionary * obj2) {
// are points equal?
if ([obj1[#"count"] intValue] != [obj2[#"count"] intValue]) {
// points not equal, compare points
if ([obj1[#"count"] intValue] > [obj2[#"count"] intValue])
return (NSComparisonResult)NSOrderedAscending;
else
return (NSComparisonResult)NSOrderedDescending;
}
else {
return (NSComparisonResult)NSOrderedSame;
}
}];
Let me know how it goes!
Okay, just to add to what others had posted (Thank you!) i also found my own solution which goes like this:
NSArray *keysByFrequency = [object keysSortedByValueUsingComparator:^NSComparisonResult(NSDictionary* obj1, NSDictionary* obj2) {
return [obj1[#"count"] compare:obj2[#"count"]];
}];
NSMutableArray *tags = [[NSMutableArray alloc] init];
for (int i = keysByFrequency.count-1; i >= 0; i--) {
[tags addObject:#{#"tag" : keysByFrequency[i], #"count" : object[keysByFrequency[i]][#"count"], #"type" : object[keysByFrequency[i]][#"type"]}];
}

NSSortDescriptor sort with number as string?

Got a an Array full of dictionary likes this:
(
{ order = "10";
name = "David"
};
{ order = "30";
name = "Jake";
};
{ order = "200";
name = "Michael";
};
)
When i'm using NSSortDescriptor like the code below it only sorts regarding to the first char so 200 is lower then 30. I can of course change the "order" object into a NSNumber instead of string and it would work. But is there a way to sort a string as int values without changing the source object?
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"norder" ascending:YES];
[departmentList sortUsingDescriptors:[NSArray arrayWithObjects:descriptor,nil]];
Update:
Thanks to bandejapaisa.
Here is the a working version for iOS 5 (Xcode where compalining).
NSArray *sortedArray;
sortedArray = [departmentList sortedArrayUsingComparator:(NSComparator)^(id a, id b) {
NSNumber *num1 = [NSNumber numberWithInt:[[a objectForKey:#"norder"] intValue]];
NSNumber *num2 = [NSNumber numberWithInt:[[b objectForKey:#"norder"] intValue]];
return [num1 compare:num2];
}];
departmentList = [sortedArray mutableCopy];
Using a NSNumber is overkill. You can save yourself a lot of overhead by doing the following:
NSArray *sortedArray = [someArray sortedArrayUsingComparator:^(id obj1, id obj2) {
return (NSComparisonResult) [obj1 intValue] - [obj2 intValue];
}];
Maybe sort using a comparator instead, or one of the other sorting methods:
NSArray *sortedArray = [someArray sortedArrayUsingComparator:^(id obj1, id obj2) {
NSNumber *num1 = [NSNumber numberWithInt:[obj1 intValue]];
NSNumber *num2 = [NSNumber numberWithInt:[obj2 intValue]];
return (NSComparisonResult)[rank1 compare:num2];
}];
All the above methods need good knowledge in basics to implement, but for the freshers i suggest the most simplest way is to use the native block method, hope this helps
NSArray* sortedArr =[fetchResults sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
int aValue = [[a valueForKey:#"subgroupId"] intValue];
int bValue = [[b valueForKey:#"subgroupId"] intValue];
return aValue>bValue; }];
Happy Coding...

Can make custom comparator such as "caseInsensitiveCompare" in sorting?

I trying to sort some data to use sortedArrayUsingDescriptors: method in an NSArray class.
That method must need to indicate standard comparator, but I want to indicate custom comparator what I make.
Is possible?
Here is part of my sorting code:
NSSortDescriptor *firstDescriptor =
[[[NSSortDescriptor alloc]
initWithKey:FIRSTNAME
ascending:YES
selector:#selector(CustomCompare:)] autorelease];
CustomCompare: <= want to make custom comparator.
Why not use the sortedArrayUsingComparator: and implement your comparator to be case-insensitive? Something like this:
NSArray *sortedArray = [myArray sortedArrayUsingComparator:^(id o1, id o2) {
NSString *str1 = (NSString *)o1;
NSString *str2 = (NSString *)o2;
return [str1 compare:str2 options:NSCaseInsensitiveSearch];
}];
update
For more complex classes, multiple comparison fields may also be used:
NSArray *sortedArray = [myArray sortedArrayUsingComparator:^(id o1, id o2) {
MyClass *cl1 = (MyClass *)o1;
MyClass *cl2 = (MyClass *)o2;
NSComparisonResult result = [cl1.primaryString compare:cl2.primaryString options:NSCaseInsensitiveSearch];
if (result == NSOrderedSame) {
result = [cl1.secondaryString compare:cl2.secondaryString options:NSCaseInsensitiveSearch];
}
return result;
}];

Sort an NSArray with NSDictionary

I'm using NSSortDiscriptors to sort an NSArray.
Every index in the array contains a dictionary with key,value entries. This dictionary also holds another dictionary.
My problem that I want solve is to sort the array based on values on the first dictionary, but also on some values in the dictionary it contains.
The following is the sort method I use for the other values in the array.
- (void)sortArray {
if ([array count] != 0) {
// Reports sortingDescriptors
NSSortDescriptor * city = [[NSSortDescriptor alloc] initWithKey:#"City" ascending:YES];
NSSortDescriptor * name = [[NSSortDescriptor alloc] initWithKey:#"Name" ascending:YES];
NSSortDescriptor * country = [[NSSortDescriptor alloc] initWithKey:#"Country" ascending:YES];
[reportsArray sortUsingDescriptors:[NSArray arrayWithObjects:city, name, country, nil]];
[name release];
[city release];
[country release];
}
}
The array looks like this:
[{name = "";
city = "";
country = "";
date = {
dateAdded = "";
dateRemoved = "";
}
}];
So I also want to sort on, if have value on dateAdded for example.
You can specify a key path when you create the NSSortDescriptor, this way you can sort the NSArray with a NSDictionary.
You might want to check if the dictionary contains a value like that :
// you can't set nil as a value for a key
if([yourDictionary objectForKey:#"yourKey"] == [NSNull null]) { ... }
Then you need to sort remaining objects but the dictionary, to do so, make a copy of your array without the dictionary entry by doing something like :
NSMutableArray *tmpArray = [NSMutableArray arrayWithArray:firstArray];
[tmpArray removeObjectAtIndex:theIndexOfTheDictionary];
// sort your array, don't forget to catch the returned value
NSMutableArray *sortedArray = [tmpArray sortUsingDescriptors:[NSArray arrayWithObjects:city, name, country, nil]];
// finally, put the dictionary back in (if needed)
[sortedArray insertObject:theDictionary atIndex:theIndexYouWant];
Are you saying that the objects in the array have a City, Name and Country property but also a dictionary property and you want to sort on one of the keys in the dictionary? Or are you saying that the entries in the array are dictionaries but sometimes the City, Name or Country key is missing? Or are you saying that some of the entries are dictionaries and some are objects with the listed properties?
In any case, you can get more flexibility by creating a sort descriptor using initWithKey:ascending:comparator:. This allows you to supply a comparator block as the sort function which is more flexible than a straight selector e.g.
NSComparator mySort = ^(id obj1, id obj2)
{
NSComparisonResult ret = NSOrderedSame;
if ([obj1 isKindOfClass: [NSDictionary class]] && ![obj2 isKindOfClass: NSDictionary class]])
{
ret = NSOrderedAscending;
}
else if (![obj1 isKindOfClass: [NSDictionary class]] && [obj2 isKindOfClass: NSDictionary class]])
{
ret = NSOrderedDescending;
}
return ret;
};
NSSortDescriptor* descriptor = [[NSSortDescriptor alloc] initWithKey: #"self" ascending: YES comparator: mySort];
will give you a sort descriptor that sorts the array putting all the NSDictionaries first and other objects afterwards. (self is a key possessed by all NSObjects that returns the object itself).
NSArray *unsortedArray=[NSArray arrayWithObjects:[NSDictionary dictionaryWithObjectsAndKeys:#"anil",#"personInDictionary.lastName" ,nil],[NSDictionary dictionaryWithObjectsAndKeys:#"aneelu",#"personInDictionary.lastName", nil] ,[NSDictionary dictionaryWithObjectsAndKeys:#"kumar",#"anil.lastName", nil] ,nil];
NSSortDescriptor * descriptor = [[[NSSortDescriptor alloc] initWithKey:#"personInDictionary.lastName" ascending:YES] autorelease]; // 1
NSArray * sortedArray = [unsortedArray sortedArrayUsingDescriptors:
[NSArray arrayWithObject:descriptor]];
NSLog(#"sortedArray values %#",sortedArray);
for (id object in [sortedArray valueForKey:#"personInDictionary.lastName"]) {
NSLog(#"sortedArray value %#",object);
}

Sorting array(NSArray) in descending order

I have a array of NSString objects which I have to sort by descending.
Since I did not find any API to sort the array in descending order I approached by following way.
I wrote a category for NSString as listed bellow.
- (NSComparisonResult)CompareDescending:(NSString *)aString
{
NSComparisonResult returnResult = NSOrderedSame;
returnResult = [self compare:aString];
if(NSOrderedAscending == returnResult)
returnResult = NSOrderedDescending;
else if(NSOrderedDescending == returnResult)
returnResult = NSOrderedAscending;
return returnResult;
}
Then I sorted the array using the statement
NSArray *sortedArray = [inFileTypes sortedArrayUsingSelector:#selector(CompareDescending:)];
Is this right solution? is there a better solution?
You can use NSSortDescriptor:
NSSortDescriptor* sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:nil ascending:NO selector:#selector(localizedCompare:)];
NSArray* sortedArray = [inFileTypes sortedArrayUsingDescriptors:#[sortDescriptor]];
Here we use localizedCompare: to compare the strings, and pass NO to the ascending: option to sort in descending order.
or simplify your solution:
NSArray *temp = [[NSArray alloc] initWithObjects:#"b", #"c", #"5", #"d", #"85", nil];
NSArray *sortedArray = [temp sortedArrayUsingComparator:
^NSComparisonResult(id obj1, id obj2){
//descending order
return [obj2 compare:obj1];
//ascending order
return [obj1 compare:obj2];
}];
NSLog(#"%#", sortedArray);
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"length" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[wordsArray sortUsingDescriptors:sortDescriptors];
Using this code we can sort the array in descending order on the basis of length.