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

前端 未结 5 600
心在旅途
心在旅途 2020-12-02 02:10

I have some data like this :

1, 111, 2, 333, 45, 67, 322, 4445

NSArray *array = [[myData allKeys]sortedArrayUsingSelector: @selector(compare:)];


        
相关标签:
5条回答
  • 2020-12-02 02:40

    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);
    
    0 讨论(0)
  • 2020-12-02 02:41

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

    0 讨论(0)
  • 2020-12-02 02:42

    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];
    }
    
    0 讨论(0)
  • 2020-12-02 02:50

    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)
        }
    }
    
    0 讨论(0)
  • 2020-12-02 02:51

    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.

    0 讨论(0)
提交回复
热议问题