Sort an NSArray in Descending Order - iphone

I have an NSArray of NSNumber objects that I have successfully sorted in ascending order using the following:
[myArray sortedArrayUsingSelector:#selector(compare:)]
However, I need to sort this in descending order. I take it that compare: only sorts in ascending order. While I can go about reversing the NSArray, I am curious as to whether or not there is a more simpler or more effective way of going about doing this.
EDIT: I found this question which provides a simple way to reverse iterate an NSArray:
for (id someObject in [myArray reverseObjectEnumerator])
This works fine, I guess it's a nice simple solution, but I'm curious as to whether or not there is a way to specify sorting in descending order.

Use a sort descriptor
NSSortDescriptor* sortOrder = [NSSortDescriptor sortDescriptorWithKey: #"self"
ascending: NO];
return [myArray sortedArrayUsingDescriptors: [NSArray arrayWithObject: sortOrder]];

Another way, imo, is also nice: write another reverseCompare with category:
#implementation NSNumber (Utility)
- (NSComparisonResult)reverseCompare:(NSNumber *)aNumber {
return [aNumber compare:self];
}
The good thing is that you can reuse everywhere and don't have to write the loop with reverse iterate. The bad thing is that you have to write more code:)

use sortarrayusingcomparator method like that
NSArray *sortedArray = [array sortedArrayUsingComparator:
^NSComparisonResult(id obj1, id obj2){
return [obj2 compare:obj1];
}];
by reversing the order of objects you will obtain a descending order

There are a few ways:
Write a comparison function and pass it to sortUsingFunction:context:.
Use sortUsingComparator:, which takes a block. (Only available in Mac OS X 10.6 and later and iOS 4.0 and later.)
Use sortUsingDescriptors:, and pass an array of at least one sort descriptor whose ascending property is false.
In the first two cases, your comparison should simply return the negation of what the comparator you normally use (e.g., compare:) returned. The last one involves less custom code, so it's what I'd use.

I have a mutableArray and want to sort in descending order with "number" key. "number" key is a string like "12345", "12346". This way that I had tried and look very well. Hope help you!
NSComparisonResult result;
NSArray *arrTem = [multableArr sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
if([obj1 valueForKey:#"number"] > [obj2 valueForKey:#"number"])
result = NSOrderedDescending;
result = NSOrderedSame;
}];
return [[NSMutableArray alloc]initWithArray:arrTem];

For Example Data is Like this and we want to sort NSArray based on sId key.
<__NSArrayM 0x7ffc725af1d0>(
{
sId = 3;
vName = ABC;
},
{
sId = 10;
vName = DEF;
},
{
sId = 9;
vName = GHI;
},
{
sId = 7;
vName = JKL;
},
{
sId = 1;
vName = MNO;
}
)
Solution is as Below
NSArray *sortedArray = [arrOptions sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
if ([[obj1 valueForKey:#"sId"] integerValue] > [[obj2 valueForKey:#"sId"] integerValue]) {
return (NSComparisonResult)NSOrderedDescending;
}
if ([[obj1 valueForKey:#"sId"] integerValue] < [[obj2 valueForKey:#"sId"] integerValue]) {
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
}];
NSLog(#"Sorted Service Array is ::%#",sortedArray);

comare selector has to return NSComparisonResult. It's actually your function, so you can write another function, that returns the opposite result to sort in descending order.

The Dr. Touch website has a nice implementation of a category on NSArray to create a self-sorting array. This could be modified to keep the sort in whatever order was appropriate.

If you need based on ABCD in ascending then use following code
NSSortDescriptor *descriptor=[[NSSortDescriptor alloc] initWithKey:#"self" ascending:YES];
NSArray *descriptors=[NSArray arrayWithObject: descriptor];
NSArray *reverseOrder=[yourArray sortedArrayUsingDescriptors:descriptors];

we can do it simply by using sortUsingSelector. The code as follows;
NSMutableArray *arr=[[NSMutableArray alloc]initWithObjects: ..objects.. ];
//Can also use NSArray.
[arr sortUsingSelector:#selector(compare:options:)];
NSString *temp;
int i,j;
i=0;
j=[arr count];
for(i=0;i<([arr count]-1);i++)
{
temp=[arr objectAtIndex:i];
[arr replaceObjectAtIndex:i withObject:[arr objectAtIndex:j]];
[arr replaceObjectAtIndex:j withObject:temp];
j--;
}
NSLog(#"New array is:%#",arr);
You may think that WHAT A STUPID ANSWER it is :D :D Actually, am not teasing anyone. But in simple logic, we can sort array in descending order by this way. No need of using any type of descriptors or any other complicated stuffs. And it will be easier for entry level programmers.

Use the following code to sort Array on the basis of key on which you want to sort tge array (e.g name , code, address,emp_id etc...)
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"Enter Sort Type" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
return [array sortedArrayUsingDescriptors:sortDescriptors];

Related

Sorting Multiple NSMutableArray's

I have 3 MutableArray's Named:
tvShows
tvNetworks
tvdbID
I need to sort them by the name of the tvShows.
But the need to stay linked.
So e.g.:
tvShows = Breaking Bad, House, Community;
tvNetworks = AMC, FOX, NBC;
tvdbID = 81189, 73255, 94571;
Needs To Become:
tvShows = Breaking Bad, Community, House;
tvNetworks = AMC, NBC, FOX;
tvdbID = 81189, 94571, 73255;
How would I do this? It's my first app so sorry if it's a realy easy question.
store them in an array of dictionaries then sort with an NSArray sort function: (below)
NSDictionary * dict1 = #{#"title":#"breaking bad",#"network":#"AMC",#"tvbdID":#(81189)};
NSDictionary * dict2 = #{#"title":#"house",#"network":#"FOX",#"tvbdID":#(73255)};
NSDictionary * dict3 = #{#"title":#"Community",#"network":#"NBC",#"tvbdID":#(94571)};
NSArray * array = #[dict1,dict2,dict3];
NSSortDescriptor * desc = [NSSortDescriptor sortDescriptorWithKey:#"title"ascending:YES selector:#selector(caseInsensitiveCompare:)];
NSArray * sortedArray = [array sortedArrayUsingDescriptors:#[desc]];
I would personally create a custom NSObject called TVShow, that has properties of showName, network, and tvbdID. This way, you only have one array of each show. Assuming your array is called myShows, you could do something like this:
[allShows sortUsingComparitor:^NSComparisonResult(id a, id b) {
NSString *firstName = [(TVShow*)a showName];
NSString *secondName = [(TVShow*)b showName];
return [firstName compare: secondName];
}];
That is, if you wanted to sort by show name. You can swap network for showName if you wanted to sort by network!
No idea what your end goal is, but you should probably create a TVShow class that has properties (i.e., instance variables) for "title," "network", and "dbid." Then you can instantiate three TVShow objects with their appropriate properties, put them in a mutable array, and use one of the sorting methods on NSMutableArray -- I'd probably choose sortUsingComparator:.
you can't do it with 3 independent arrays but maybe with 1 dictionary where the keys are tv shows and the value is a dictionary with 2 keys: tvNetworks & tvdbIDs
sample:
NSDictionary *data = #{#"Breaking Bad":#{#"tv" : #"AMC", #"tvdb": #(81189)},
#"House":#{#"tv" : #"FOX", #"tvdb": #(73255)},
#"Community":#{#"tv" : #"NBC", #"tvdb": #(94571)}};
NSArray *sortedShows = [data.allKeys sortedArrayUsingSelector:#selector(compare:)];
for (id show in sortedShows) {
NSLog(#"%# = %#", show, data[show]);
}
One of the easiest and most straightforward ways to do this would be to create one array of dictionaries, like this:
NSMutableArray *tvShowInfos = [NSMutableArray array];
for (NSInteger i = 0; i < tvShows.count; i++) {
NSDictionary *info = #{#"show": [tvShows objectAtIndex:i],
#"network": [tvNetworks objectAtIndex:i],
#"id": [tvdbIDs objectAtIndex:i]};
[tvShowInfos addObject:info];
}
You can then sort that array easily:
[tvShowInfos sortUsingDescriptors:#[ [[NSSortDescriptor alloc] initWithKey:#"show" ascending:YES] ]];
If you need an array that contains all networks, sorted by show title, you can then use valueForKey: on the array of dictionaries:
NSArray *networksSortedByShow = [tvShowInfos valueForKey:#"network"];

error in array cleaning method

I am attempting to use this array cleaning method, and there seems to be an error. I can't spot it, I know the array goes in with 3116 items, comes out with 3116 (and I know for a fact there are three duplicates.
Please advice, thanks!
-(NSArray*) removeDuplicates:(NSArray*)inputArray{
NSMutableArray *arrayToClean = [NSMutableArray arrayWithArray:inputArray];
for (int i =0; i<[arrayToClean count]; i++) {
for (int j=(i+1); j < [arrayToClean count]; j++) {
if ([[arrayToClean objectAtIndex:i] isEqual:[arrayToClean
objectAtIndex:j]]) {
[arrayToClean removeObjectAtIndex:j];
j--;
}
}
}
NSArray *arrayToReturn = [NSArray arrayWithArray:arrayToClean];
return arrayToReturn;
}
NSSet will make this a lot easier:
-(NSArray *)removeDuplicates:(NSArray *)inputArray {
NSSet *unique = [NSSet setWithArray:inputArray];
return [unique allObjects];
}
Please note that a set has no guaranteed order. If you need the objects in the array to be in a specific order then you should sort the resulting array as needed.
It may also be appropriate to use an NSSet instead of the original array, then you don't need to worry about duplicates at all. But this depends on the other needs of your array.
Hey You can use another alternative for this.You can use the NSSet here for this task.
NSSet declares the programmatic interface for static sets of distinct objects
You can use sets as an alternative to arrays when the order of elements isn’t important and performance in testing whether an object is contained in the set is a consideration—while arrays are ordered, testing for membership is slower than with sets.
You Just need To call below method.
-(NSArray *)removeDuplicates:(NSArray *)inputArray {
NSSet *finalData = [NSSet setWithArray:inputArray];
return [finalData allObjects];
}
If really face any problem in above way of cleaning ducplicates then you can try another Alterantive.
-(NSArray *)removeDuplicates:(NSArray *)inputArray {
NSMutableArray *inputArray1=[NSMutableArray arrayWithArray:inputArray];
NSMutableArray *finalARray=[[NSMutableArray alloc]init];
for (id obj in inputArray1)
{
if (![finalARray containsObject:obj])
{
[finalARray addObject: obj];
}
NSLog(#"new array is %#",finalARray);
}
return finalARray;
}
I hope it may help you ...
Here is a helper function I had in a previous project to do the exact same thing
- (NSMutableArray *)removeDuplicates:(NSMutableArray *)sortedArray{
NSMutableSet* valuesAdded = [NSMutableSet set];
NSMutableArray* filteredArray = [[NSMutableArray alloc] init];
NSString* object;
/* Iterate over the array checking if the value is a member of the set. If its not add it
* to the set and to the returning array. If the value is already a member, skip over it.
*/
for (object in sortedArray){
if (![valuesAdded member:object]){
[valuesAdded addObject:object];
[filteredArray addObject:object];
}
}
return filteredArray;
}

How to sort the array in Objective C? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
How to sort array having numbers as string in iPhone?
How Do I sort an NSMutable Array with NSNumbers in it?
I have a NSMutableArray with random order of numbers. I have to sort them in ascending and descending order? Is there any in built function for that and if no how it can be done. Array is like this:
arr = ["12","85","65","73","21","87","1","34","32"];
Sorting NSMutableArray (based on key) which contains objects
First, you’ll need to create an NSSortDescriptor and tell it which key to sort the array on.
NSSortDescriptor *lastNameSorter = [[NSSortDescriptor alloc] initWithKey:#"lastName" ascending:YES];
[personList sortUsingDescriptors:[NSArray arrayWithObject:lastNameSorter]];
Hope this Full tutorial helps you.
use sortUsingSelector instance method of class NSMutableArray.
use this line (But you need to use NSNumbers rather than string in case of numbers)
[myArray sortUsingSelector:#selector(compare:)];
It sort array in ascending order. for descending order add this line after above line.
myArray=[myArray reverseObjectEnumerator] allObjects];
example code for your case:
NSArray *sortedArray;
sortedArray = [anArray sortedArrayUsingFunction:intSort context:NULL];
NSInteger intSort(id num1, id num2, void *context)
{
int v1 = [num1 intValue];
int v2 = [num2 intValue];
if (v1 < v2)
return NSOrderedAscending;
else if (v1 > v2)
return NSOrderedDescending;
else
return NSOrderedSame;
}
you can develop a logic to sort your array in intsort method and pass it as parameter to above method.
there are many predefined methods like:
sortUsingDescriptors:
sortUsingComparator:
sortWithOptions:usingComparator:
sortUsingFunction:context:
sortUsingSelector:
follow developer.apple.com for api
good luck TNX

Sort an array with numeric strings

Hello I have an array of persons, and i am trying to sort them by age using a sort descriptor.
The age field in a patient is a string so when calling:
ageSorter = [[NSSortDescriptor alloc] initWithKey:#"age" ascending:YES];
[personList sortUsingDescriptors:[NSArray arrayWithObject:ageSorter]];
It sorts them but 100 appears first because its is not using numericSearch in the compare options.
Is there a ways i can still sort with descriptor but maybe using a selector to change how to compare the strings?
The finderSortWithLocale method (both these are taken from apple api):
int finderSortWithLocale(Person *person1, Person *person2, void *locale)
{
static NSStringCompareOptions comparisonOptions = NSNumericSearch;
NSRange string1Range = NSMakeRange(0, [string1 length]);
NSString *age1 = person1.age;
NSString *age2 = person2.age;
return [age1 compare:age2
options:comparisonOptions
range:string1Range
locale:(NSLocale *)locale];
}
How to call this method (edited: call the function on array of Persons):
NSArray *sortedArray = [personList sortedArrayUsingFunction:finderSortWithLocale
context:[NSLocale currentLocale]];
I also faced the same issue and found answer here.
Instead of NSString comparison, do with your object property. i.e for age.
Example. : In ascending order :
NSArray *sortedArray = [_arrayCaptureLeadList sortedArrayUsingComparator:^(Person *obj1, Person *obj2) {
return [obj1.age compare:obj2.age options:NSNumericSearch];
}];
NSMutableArray *filterResultArray = [NSMutableArray arrayWithArray:sortedArray];
In descending order :
NSArray *sortedArray = [_arrayCaptureLeadList sortedArrayUsingComparator:^(Person *obj1, Person *obj2) {
return [obj2.age compare:obj1.age options:NSNumericSearch];
}];
NSMutableArray *filterResultArray = [NSMutableArray arrayWithArray:sortedArray];
I know this is very late to reply your question but may this will be helpful for others. ^_^
You could create a category on NSString that adds a method numericCompare: and which calls [self compare:otherString options:NSNumericSearch]. Another option is to convert the age field into a NSNumber instead of a NSString. Yet another option involves a NSComparator block and sortUsingComparator.

How Do I sort an NSMutable Array with NSNumbers in it?

I'm trying to make a high score table, and suck at arrays in objective c (actually, in general objective c is challenging for me), so I can't figure out how to sort. I'm trying to do something like this (speudocode, I'm writing this in actionscript style because I'm more comfortable with it):
highscores.addObjecttoArray(score)
highscores.sort(ascending)
But I can't figure it out... I've seen other threads about it, but their use plist files and stuff and I don't know enough objective c to learn from them.
Would you like to do that the short way?
If you have a mutable array of NSNumber instances:
NSSortDescriptor *highestToLowest = [NSSortDescriptor sortDescriptorWithKey:#"self" ascending:NO];
[mutableArrayOfNumbers sortUsingDescriptors:[NSArray arrayWithObject:highestToLowest]];
Nice and easy :)
You can also perform similar sorting with descriptors on immutable arrays, but you will end up with a copy, instead of in-place sorting.
[highscores sortUsingSelector:#selector(compare:)];
Should work if they're definitely all NSNumbers.
(Adding an object is:
[highscores addObject:score];
)
If you want to sort descending (highest-first):
10.6/iOS 4:
[highscores sortUsingComparator:^(id obj1, id obj2) {
if (obj1 > obj2)
return NSOrderedAscending;
else if (obj1 < obj2)
return NSOrderedDescending;
return NSOrderedSame;
}];
Otherwise you can define a category method, e.g.:
#interface NSNumber (CustomSorting)
- (NSComparisonResult)reverseCompare:(NSNumber *)otherNumber;
#end
#implementation NSMutableArray (CustomSorting)
- (NSComparisonResult)reverseCompare:(NSNumber *)otherNumber {
return [otherNumber compare:self];
}
#end
And call it:
[highscores sortUsingSelector:#selector(reverseCompare:)];
I tried the answer provided by ohhorob, but the objects were still being sorted alphabetically. Then I ran across this in another answer (https://stackoverflow.com/a/4550451/823356):
I changed my NSSortDescriptor and it now sorts numerically.
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"score"
ascending:YES
comparator:^(id obj1, id obj2) {
return [obj1 compare:obj2 options:NSNumericSearch];
}];
I just thought I'd drop this in here as it solved my 'alphabetical sorting of NSNumbers' problem
For all it's worth, here is another shorthand method:
NSArray* n = #[#8, #3, #1, #12, #16, #7, #0, #5];
NSArray* asc = [n sortedArrayUsingComparator:^NSComparisonResult(NSNumber* n1, NSNumber* n2) {
return [n1 compare:n2];
}];
NSLog(#"Ascending: %#", asc);
NSArray* dec = [n sortedArrayUsingComparator:^NSComparisonResult(NSNumber* n1, NSNumber* n2) {
return [n2 compare:n1];
}];
NSLog(#"Descending: %#", dec);
This code will sort an NSMutableArray of NSNumber in ascending order:
[tempRA sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2];
}];
This code will sort an NSMutableArray of NSNumber in descending order:
[tempRA sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2] * -1; // reverse the enum
}];
The code uses the fact that the NSNumber compare: method returns an NSComparisonResult that ranges from -1 to 1. Multiplying the result of the compare by -1 reverses the result and thereby reverses the sort to descending order.
distance is a key and it's value link (float or double)
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"distance"
ascending:YES
comparator:^(id obj1, id obj2)
{
return [obj1 compare:obj2 options:NSNumericSearch];
}];
NSArray *myArray = [NSArray arrayWithArray:arraySubCat];
myArray=[myArray sortedArrayUsingDescriptors:[NSArray arrayWithObjects:sortDescriptor,nil]];
arraySubCat = [myArray copy];
For Descending Order:
NSArray *DescendingArray = [MinMaxArray sortedArrayUsingDescriptors:
#[[NSSortDescriptor sortDescriptorWithKey:#"doubleValue"
ascending:NO]]];
For ascending Order
NSArray *AscendingArray = [MinMaxArray sortedArrayUsingDescriptors:
#[[NSSortDescriptor sortDescriptorWithKey:#"doubleValue"
ascending:YES]]];