如何让sortedArrayUsingSelector使用整数来排序而不是String?

时间:2010-05-02 09:30:11

标签: iphone sorting nsarray

我有一些这样的数据:

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

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

如果我运行此代码,它的排序方式如下:

  

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

但我真的想要这个:

  

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

我该如何实施?你好。

5 个答案:

答案 0 :(得分:21)

扩展保罗林奇的答案,这是一个例子我使用比较方法作为NSString上的类别正是这样做的。此代码仅处理数字后跟可选的非数字限定符的情况,但如果需要,您可以扩展它以处理“1a10”等情况。

创建类别方法后,您只需要

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

答案 1 :(得分:14)

您可以使用NSString的-[compare:options:]函数和NSNumericSearch选项以数字方式比较NSStrings,而不必先将它们转换为NSIntegers(这可能非常昂贵,尤其是在较长的循环中)。

由于你想使用NSArray,你可以使用NSSortDescriptor的+[sortDescriptorWithKey:ascending:comparator:](如果你想要一个预先保留的对象,可以使用相同的-initWithKey:ascending:comparator:函数来执行基于块的比较:

[NSSortDescritor sortDescriptorWithKey:@"myKey"
                             ascending:NO
                            comparator:^(id obj1, id obj2)
    {
        return [obj1 compare:obj2 options:NSNumericSearch];
    }
];

使用此方法排序将得到与David的答案相同的结果,但无需亲自处理NSScanner。

答案 2 :(得分:0)

实现自己的方法,返回NSComparisonResult。如果您愿意,它可以属于一个类别。

答案 3 :(得分:0)

排序和简单解决方案..

    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);

答案 4 :(得分:0)

大卫的answer为我做了伎俩。对于它的价值,我想分享相同答案的Swift 1.0版本。

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)
    }
}