Как разрешить sortedArrayUsingSelector использовать целое число для сортировки вместо строки?

У меня есть такие данные:

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

Как я могу это реализовать? тц у.


person Tattat    schedule 02.05.2010    source источник
comment
К какому классу относятся объекты в массиве — NSString или NSNumber?   -  person sbooth    schedule 02.05.2010
comment
это NSString... ...но я не хочу менять на NSNumber. Это потому, что в будущем у него могут быть некоторые данные, такие как 1a....   -  person Tattat    schedule 02.05.2010
comment
Как сортировка 1a связана с 1 и 10?   -  person mmmmmm    schedule 02.05.2010
comment
1, 1a, 10.... ...Сначала отсортируйте число.   -  person Tattat    schedule 02.05.2010


Ответы (5)


Расширяя ответ Пола Линча, вот пример, который я делаю именно так, используя метод сравнения в качестве категории на 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];
}
person David Gelhar    schedule 03.05.2010
comment
Это действительно потрясающе. Просто работает! - person Tattat; 04.05.2010
comment
Работает как шарм... отлично! - person allemattio; 05.12.2013

Вы можете использовать функцию -[compare:options:] NSString и параметр NSNumericSearch для численного сравнения NSString без необходимости сначала преобразовывать их в NSInteger (что может быть довольно дорого, особенно в более длинных циклах).

Поскольку вы хотите использовать 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 самостоятельно.

person liclac    schedule 08.03.2011

Реализуйте свой собственный метод, который возвращает NSComparisonResult. Это может быть в категории, если вы хотите.

person Paul Lynch    schedule 02.05.2010

Сортировка и простое решение..

    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);
person Vishal Vaghasiya    schedule 06.05.2014

ответ Дэвида помог мне. Что бы это ни стоило, я хочу поделиться версией 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)
    }
}
person Lester    schedule 30.09.2015