How to let the sortedArrayUsingSelector using integer to sort instead of String?

☆樱花仙子☆ 提交于 2019-12-17 09:59:42

问题


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.


回答1:


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];
}



回答2:


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.




回答3:


Implement your own method that returns NSComparisonResult. It can be in a category if you wish.




回答4:


Sort and Simple Solution..

    NSSortDescriptor *sortDescriptor;
    sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"self"
                                                   ascending:YES
                                                  comparator:^(id obj1, id obj2) {
                                                      return [obj1 compare:obj2 options:NSNumericSearch];
                                                  }];
    NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
    NSArray *sortedArray;
    sortedArray = [montharray
                   sortedArrayUsingDescriptors:sortDescriptors];
    [montharray removeAllObjects];
    [montharray addObjectsFromArray:sortedArray];

    NSLog(@"MONTH ARRAY :%@",montharray);



回答5:


David's answer did the trick for me. For what it's worth, I want to share the Swift 1.0 version of the same answer.

extension NSString {
    func psuedoNumericCompare(otherString: NSString) -> NSComparisonResult {
        var left: NSString = self
        var right: NSString = otherString
        var leftNumber: Int = self.integerValue
        var rightNumber: Int = otherString.integerValue

        var leftScanner: NSScanner = NSScanner(string: left)
        var rightScanner: NSScanner = NSScanner(string: right)

        if leftScanner.scanInteger(&leftNumber) && rightScanner.scanInteger(&rightNumber) {
            if leftNumber < rightNumber {
                return NSComparisonResult.OrderedAscending
            }
            if leftNumber > rightNumber {
                return NSComparisonResult.OrderedDescending
            }

            left = left.substringFromIndex(leftScanner.scanLocation)
            right = right.substringFromIndex(rightScanner.scanLocation)
        }
        return left.caseInsensitiveCompare(right)
    }
}


来源:https://stackoverflow.com/questions/2752992/how-to-let-the-sortedarrayusingselector-using-integer-to-sort-instead-of-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!