I have some data like this :
1, 111, 2, 333, 45, 67, 322, 4445
NSArray *array = [[myData allKeys]sortedArrayUsingSelector: @selector(compare:)];
If I run this code, it sorted like this:
1, 111, 2,322, 333, 4445, 45, 67,
but I actually want this:
1, 2, 45, 67, 111, 322, 333, 4445
How can I implement it? thz u.
Expanding on Paul Lynch's answer, here's an example I have doing exactly this using a comparison method as a category on NSString
. This code handles only the case of numbers followed by optional non-numeric qualifiers, but you could extend it to handle cases like "1a10" etc. if desired.
Once you create the category method, you just need to do
[[myData allKeys]sortedArrayUsingSelector:@selector(psuedoNumericCompare:)];
@interface NSString (Support)
- (NSComparisonResult) psuedoNumericCompare:(NSString *)otherString;
@end
@implementation NSString (Support)
// "psuedo-numeric" comparison
// -- if both strings begin with digits, numeric comparison on the digits
// -- if numbers equal (or non-numeric), caseInsensitiveCompare on the remainder
- (NSComparisonResult) psuedoNumericCompare:(NSString *)otherString {
NSString *left = self;
NSString *right = otherString;
NSInteger leftNumber, rightNumber;
NSScanner *leftScanner = [NSScanner scannerWithString:left];
NSScanner *rightScanner = [NSScanner scannerWithString:right];
// if both begin with numbers, numeric comparison takes precedence
if ([leftScanner scanInteger:&leftNumber] && [rightScanner scanInteger:&rightNumber]) {
if (leftNumber < rightNumber)
return NSOrderedAscending;
if (leftNumber > rightNumber)
return NSOrderedDescending;
// if numeric values tied, compare the rest
left = [left substringFromIndex:[leftScanner scanLocation]];
right = [right substringFromIndex:[rightScanner scanLocation]];
}
return [left caseInsensitiveCompare:right];
}
You can use NSString's -[compare:options:]
function and the NSNumericSearch
option to compare NSStrings numerically, without having to convert them to NSIntegers first (which can be quite expensive, especially in longer loops).
Since you want to use an NSArray, you can use NSSortDescriptor's +[sortDescriptorWithKey:ascending:comparator:]
(or the identical -initWithKey:ascending:comparator:
if you want a pre-retained object) function to do block-based comparisation like this:
[NSSortDescritor sortDescriptorWithKey:@"myKey"
ascending:NO
comparator:^(id obj1, id obj2)
{
return [obj1 compare:obj2 options:NSNumericSearch];
}
];
Sorting using this method will give the same results as David's answer, but without having to deal with NSScanner yourself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With