rdurand
rdurand

Reputation: 7410

Sort a NSArray of numbers in ascending order but send zeros at the end

I have a simple NSArray, containing NSNumbers.

I sort the array in an ascending order this way :

NSSortDescriptor *lowestToHighest = [NSSortDescriptor sortDescriptorWithKey:@"self" ascending:YES];
[_scores sortUsingDescriptors:[NSArray arrayWithObject:lowestToHighest]];

My problem is, I'd like the NSNumbers containing 0 to be at the end rather than at the beginning. Here is the kind of array I may have to sort (containing some empty NSNumbers just for the example):

0
25
12
0
8
0

My code of course sorts the array like this:

0
0
0
8
12
25

What I would like is this:

8
12
25
0
0
0

Of course I could re-order it manually by removing the lines with 0 and adding them at the end, but I'm looking for the cleanest solution possible.

Upvotes: 0

Views: 7006

Answers (5)

JeremyP
JeremyP

Reputation: 86651

Sort the array using a comparator.

NSArray *sortedArray = [array sortedArrayUsingComparator: ^(id obj1, id obj2) {

    if ([obj1 integerValue] == 0 && [obj2 integerValue] == 0)
    {
        return (NSComparisonResult)NSOrderedSame;
    }
    if ([obj1 integerValue] == 0)
    {
        return (NSComparisonResult)NSOrderedDescending;            
    }
    if ([obj2 integerValue] == 0)
    {
         return (NSComparisonResult)NSOrderedAscending;
    }

    if ([obj1 integerValue] > [obj2 integerValue]) 
    {
        return (NSComparisonResult)NSOrderedDescending;
    }

    if ([obj1 integerValue] < [obj2 integerValue]) 
    {
        return (NSComparisonResult)NSOrderedAscending;
    }
    return (NSComparisonResult)NSOrderedSame;
}];

Upvotes: 13

Monolo
Monolo

Reputation: 18253

@JeremyP's answer provides proper sorting, and is probably what you are after.

However, for completeness a way to do it with filters and the standard compare: method:

NSArray *numbers = @[@12, @0, @10, @15, @0, @3];

NSArray *sortedPositiveNumbers = [[numbers filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self > 0"]] sortedArrayUsingSelector:@selector(compare:)];
NSArray *zeroes = [numbers filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self = 0"]];

NSArray *result = [sortedPositiveNumbers arrayByAddingObjectsFromArray:zeroes];

Thanks to Caleb for the spark.

Upvotes: 1

Mr. Frank
Mr. Frank

Reputation: 288

You can use NSPredicate to filter the values you do not want..

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self > 0"];
NSMutableArray *filteredArray = [[_scores filteredArrayUsingPredicate:predicate] mutableCopy];
NSSortDescriptor *lowestToHighest = [NSSortDescriptor sortDescriptorWithKey:@"self" ascending:YES];
[filteredArray sortUsingDescriptors:[NSArray arrayWithObject:lowestToHighest]];

Upvotes: 0

Thilina Chamath Hewagama
Thilina Chamath Hewagama

Reputation: 9040

This will solve your problem,

NSArray *sortedScores = [_scores sortedArrayUsiHelperComparator:^(id obj1, id obj2){
    if([obj1 integerValue]==0 && [obj2 integerValue]==0){
        return (NSComparisonResult) NSOrderedSame;
    }else if([obj1 integerValue]==0){
        return (NSComparisonResult) NSOrderedDescending;
    }else if([obj2 integerValue]==0){
        return (NSComparisonResult) NSOrderedAscending;
    }
    if([obj1 integerValue] >[obj2 integerValue]) return (NSComparisonResult) NSOrderedDescending;
    if([obj1 integerValue] <[obj2 integerValue]) return (NSComparisonResult) NSOrderedAscending;
    return (NSComparisonResult) NSOrderedSame;

}];

Upvotes: 4

Caleb
Caleb

Reputation: 124997

Method 1:

  • Step 1: sort the array.

  • Step 2: move the zeroes to the end of the array.

Method 2:

  • Step 1: write a comparator function that orders 0 after any other value.

  • Step 2: sort the array.

Upvotes: 1

Related Questions