2010-05-02 3 views
6

Tengo algunos datos como estos:¿Cómo dejar que sortedArrayUsingSelector use enter para ordenar en lugar de String?

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

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

Si me quedo este código, ordenados así:

1, 111, 2322, 333, 4445, 45, 67,

pero en realidad quiero esto:

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

¿Cómo puedo ponerlo en práctica? thz u.

+0

¿De qué clase son los objetos en la matriz: NSString o NSNumber? – sbooth

+1

es NSString ... ... pero no quiero cambiar a NSNumber. Es porque puede tener algunos datos como "1a" ... en el futuro. – Tattat

+0

¿Cómo se clasifica 1a con 1 y 10? – Mark

Respuesta

21

Ampliando la respuesta de Paul Lynch, he aquí un ejemplo de que estoy haciendo exactamente esto usando un método de comparación como categoría en NSString. Este código maneja solo el caso de números seguidos por calificadores no numéricos opcionales, pero puede extenderlo para manejar casos como "1a10", etc., si lo desea.

Una vez creado el método de la categoría, sólo tiene que hacer

[[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

Eso es realmente sorprendente. ¡Solo funciona! – Tattat

+0

es increíble. Solo compruébalo – kumar

+0

¡Excelente, resolvió un problema que ha tenido durante años! – Tim

0

Implemente su propio método que devuelva NSComparisonResult. Puede estar en una categoría si lo desea.

14

Puede utilizar la función de NSString -[compare:options:] y la opción NSNumericSearch comparar NSStrings numéricamente, sin tener que convertirlos a NSIntegers primero (que puede ser bastante caro, especialmente en bucles más largos).

Puesto que usted desea utilizar una NSArray, puede utilizar NSSortDescriptor de +[sortDescriptorWithKey:ascending:comparator:] (o lo idéntico -initWithKey:ascending:comparator: si desea que un objeto previamente retenido) función para hacer comparisation basado en bloques de esta manera:

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

clasificación utilizando este método dará los mismos resultados que la respuesta de David, pero sin tener que lidiar con NSScanner usted mismo.

+0

Buen trabajo uppfinnarn .. funciona muy bien para mí .. –

0

Ordenar y solución simple ..

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

de David answer hizo el truco para mí. Por lo que vale, quiero compartir la versión Swift 1.0 de la misma respuesta.

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