1

I have an array of numbers and strings. like

NSArray* list = @[@"9", @"21", @"A 2-5", @"19-1", @"10", @"D 7-10", @"13-2"];

I want this array sorted as

@[@"9", @"10", @"21", @"13-2", @"19-1", @"A 2-5", @"D 7-10"];

But if I use

[list sortedArrayUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
    return [obj1 compare:obj2];
}];

I get

@[@"10", @"13-2", @"19-1", @"21", @"9", @"A 2-5", @"D 7-10"];

I get similar result too if I use

[list sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];

How can I achieve the result as I expected?

alexburtnik
  • 7,661
  • 4
  • 32
  • 70
x4h1d
  • 6,042
  • 1
  • 31
  • 46

2 Answers2

1

You were on the right track with sortedArrayUsingComparator. Here is how you can implement it:

NSArray* list = @[@"9", @"21", @"A 2-5", @"19-1", @"10", @"D 7-10", @"13-2"];
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
NSArray *sortedList = [list sortedArrayUsingComparator:^NSComparisonResult(NSString *string1, NSString *string2) {
        NSNumber *number1 = [numberFormatter numberFromString:string1];
        NSNumber *number2 = [numberFormatter numberFromString:string2];

        if (number1 && number2)
            return [number1 compare:number2];
        else if (number1)
            return NSOrderedAscending;
        else if (number2)
            return NSOrderedDescending;
        else return [string1 compare:string2];
}];
NSLog(@"sortedList: %@", sortedList);

Output:

( 9, 10, 21, "13-2", "19-1", "A 2-5", "D 7-10" )

The reason why you can't use integerValue instead of NSNumberFormatter is that, for instance, it will parse 13-2 as 13 and it will go before 21, which is not what you expect. NSNumberFormatter is a bit more flexible and will return nil if a string is not exactly a number.

alexburtnik
  • 7,661
  • 4
  • 32
  • 70
0

The issue you are facing is that you do not have "an array of numbers and strings", you have an array of Strings. They are compared based on the character sequence: compare the first character, if the first character is the same, compare the second character, etc. This results in the order you are getting.

If you want the order you specified, you will need to implement a custom comparator / sorting method (this answer shows the possibilities nicely).

Community
  • 1
  • 1
PeterB
  • 58
  • 7