x4h1d x4h1d - 1 month ago 8
iOS Question

Sort an array of numbers and strings

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?

Answer

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.

Comments