【问题标题】:How to let the sortedArrayUsingSelector using integer to sort instead of String?如何让 sortedArrayUsingSelector 使用整数而不是 String 进行排序?
【发布时间】:2010-05-02 09:30:11
【问题描述】:

我有一些这样的数据:

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

我该如何实现它?你。

【问题讨论】:

  • 数组中的对象是什么类 - NSString 或 NSNumber?
  • 它是 NSString... ...但我不想更改为 NSNumber。这是因为它将来可能会有一些像“1a”这样的数据。
  • 1a 排序如何与 1 和 10 结合起来?
  • 1, 1a, 10.... ...先排序。

标签: iphone sorting nsarray


【解决方案1】:

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

【讨论】:

  • 这真是太棒了。只是工作!
  • 像魅力一样工作......太棒了!
【解决方案2】:

您可以使用 NSString 的 -[compare:options:] 函数和 NSNumericSearch 选项对 NSString 进行数值比较,而不必先将它们转换为 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];
    }
];

使用这种方法进行排序将得到与大卫的答案相同的结果,但不必自己处理 NSScanner。

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      排序和简单的解决方案..

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

        【讨论】:

          猜你喜欢
          • 2019-09-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-06-06
          • 2021-10-23
          • 2014-06-16
          • 2020-02-10
          • 1970-01-01
          相关资源
          最近更新 更多