2010-05-02 70 views
6

我有這樣一些數據:如何讓sortedArrayUsingSelector使用整數來排序而不是String?

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

我怎樣才能實現呢?你好。

+0

數組中的對象是什麼類--NSString或NSNumber? – sbooth 2010-05-02 09:34:06

+1

這是NSString ......但我不想改成NSNumber。這是因爲它將來可能會有像「1a」這樣的一些數據。 – Tattat 2010-05-02 09:40:55

+0

1a如何與1和10共處? – Mark 2010-05-02 09:46:40

回答

21

對Paul Lynch的回答進行了擴展,下面是一個使用比較方法作爲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]; 
} 
+0

這真的很棒。正常工作! – Tattat 2010-05-04 13:57:46

+0

這是驚人的,我只是檢查它 – kumar 2012-06-13 10:52:19

+0

偉大的,解決了一個問題已經很長時間了! – Tim 2013-05-13 22:39:04

0

實施您自己的方法,返回NSComparisonResult。如果你願意,它可以在一個類別中。

14

您可以使用NSString的-[compare:options:]功能和NSNumericSearch選項數值比較NSString的,而無需將其轉換爲NSIntegers首先(這可能相當昂貴,尤其是在較長的循環中)。

由於要使用一個NSArray,可以使用NSSortDescriptor的+[sortDescriptorWithKey:ascending:comparator:](或相同-initWithKey:ascending:comparator:如果想預先保留對象)函數來完成的基於塊的comparisation這樣的:

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

使用排序這種方法會得到與David的答案相同的結果,但不必自己處理NSScanner。

+0

好作品uppfinnarn ..對我很好.. – 2011-12-15 11:07:37

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); 
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) 
    } 
} 
相關問題