0

This may be a simple question, but i don't know the way of doing sorting of array of signed integer values.

My array before sorting,

pointsAry (-2,-7,-5,0,-3,2,-1,-4,1,3,-6)

After using

NSArray * sortedArray = [pointsAry sortedArrayUsingComparator:^(id str1, id str2){
        return [(NSString *)str1 compare:(NSString *)str2 options:NSNumericSearch];
    }];

Result

sortedArray : (-1,-2,-3,-4,-5,-6,-7,0,1,2,3)

for signed values the sortedArray format is not correct, so i need like

(-7,-6,-5,-4,-3,-2,-1,0,1,2,3)

How to sort like above format ? Thanks in advance.

Venk
  • 5,949
  • 9
  • 41
  • 52

3 Answers3

5

The following comparator avoids the creation of temporary NSNumber objects:

NSArray *sortedArray = [pointsAry sortedArrayUsingComparator:^NSComparisonResult(NSString *str1, NSString *str2) {
    return my_int_compare([str1 intValue], [str2 intValue]);
}];

where

static inline int my_int_compare(int x, int y) { return (x > y) - (x < y); }

is a helper function that compares two integers and returns -1, 0, or +1 (as required for a comparator method), using the technique from

Of course the problem only arises because the array contains NSString objects. Using NSNumbers would be the better solution.

Using the NSNumericSearch option does not help because it does not treat the minus sign as part of the number.

Community
  • 1
  • 1
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Sneaky. +1, even though I'm not sure if I like the obfuscation introduced by calculating the return value. – Nikolai Ruhe Nov 26 '13 at 10:06
  • @NikolaiRuhe: Thanks for the feedback. Perhaps it is less obfuscate if the calculation of the sign is moved into a separate function (answer edited). – Martin R Nov 26 '13 at 10:27
  • There remains one caveat: Calculating the difference `[str1 intValue] - [str2 intValue]` might overflow which is undefined behavior in C. Avoiding this by using `return (a > b) - (a < b);` where `a` and `b` are just the int values of the parameters would remove the bug, yet also the readability. – Nikolai Ruhe Nov 26 '13 at 10:38
  • @NikolaiRuhe: You are right! So answer edited again: No bug (hopefully) and medium readability. – Martin R Nov 26 '13 at 10:47
4
NSArray *sortedArray = [pointsAry sortedArrayUsingComparator:^(NSString *str1, NSString *str2){
    return [@([str1 intValue]) compare:@([str2 intValue])];
}];
Venk
  • 5,949
  • 9
  • 41
  • 52
Nikolai Ruhe
  • 81,520
  • 17
  • 180
  • 200
  • Why box those in an `NSNumber`? Comparing `integerValue`s with the `<` operator is good enough. –  Nov 26 '13 at 09:31
  • @H2CO3 The comparator has to return an `NSComparisonResult`. Boxing is just the shortest way to reuse `compare:`. – Nikolai Ruhe Nov 26 '13 at 09:34
  • @H2CO3 Just subtracting the values would be nice if not only 0 and ±1 would be allowed as return values. – Nikolai Ruhe Nov 26 '13 at 09:36
  • @DavidRönnqvist There's no easy way to clamp the difference to -1 .. 1 without a temporary variable. – Nikolai Ruhe Nov 26 '13 at 09:37
  • @DavidRönnqvist It is, but this `NSComparisonResult` system Cocoa (Touch) enforces is insane: comparators are expected to return exactly -1, 0 or +1. –  Nov 26 '13 at 09:37
  • @NikolaiRuhe AFAIK the APIs that use the comparison results all work fine with int values outside the -1 to 1 range. That is of course not documented behavior – David Rönnqvist Nov 26 '13 at 09:38
  • 2
    @DavidRönnqvist Not documented == Not possible to use in production code. – Nikolai Ruhe Nov 26 '13 at 09:39
  • @NikolaiRuhe: meaning of `@`before `intValue` in `return` statement? – Preetam Jadakar Nov 26 '13 at 09:55
  • 1
    @preetam I don't understand your question. There's no @ before `intValue`. If you mean the @ before the parenthesis: That's shorthand to box the `int` values into `NSNumber`s. – Nikolai Ruhe Nov 26 '13 at 10:00
0
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:@"P3",@"P1",@"P4",@"P10", nil];
    NSMutableArray *num=[[NSMutableArray alloc]init];
    for(int i=0;i<array.count;i++)
    {
        NSString *str=array[i];
       [num addObject: [str substringFromIndex:1]];
    }



    NSArray *sortedArray = [num sortedArrayUsingComparator:^(NSString *str1, NSString *str2){
        return [@([str1 intValue]) compare:@([str2 intValue])];
    }];
    [array removeAllObjects];
    for(int i=0;i<sortedArray.count;i++)
    {
        NSString *newString = [NSString stringWithFormat:@"P%@",sortedArray[i]];


        [array addObject:newString];
    }

It's work for me

Bhumesh Purohit
  • 491
  • 1
  • 8
  • 26