2012-09-15 43 views
9

Tengo varias matrices que deben ordenarse una al lado de la otra.Ordenando dos NSArrays juntos uno al lado del otro

Por ejemplo, la primera matriz tiene nombres: @[@"Joe", @"Anna", @"Michael", @"Kim"] y y la otra matriz contiene direcciones: @[@"Hollywood bld", @"Some street 3", @"That other street", @"country road"], donde los índices de los arrays' van de la mano. "Joe" vive en "Hollywood bld", y así sucesivamente.

Me gustaría ordenar el conjunto de nombres alfabéticamente, y luego tener la matriz de direcciones ordenada al costado, por lo que todavía van juntas, con "Hollywood bld" que tiene el mismo índice que "Joe". Yo sé cómo ordenar una matriz alfabético con

NSSortDescriptor *sort=[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:NO]; 
[myArray sortUsingDescriptors:[NSArray arrayWithObject:sort]]; 

Pero ¿hay alguna manera fácil de conseguir la segunda matriz ordenada usando el orden apropiado?

Respuesta

11
  1. crear una matriz de permutación, fijado inicialmente a p[i]=i
  2. Ordenar la permutación de acuerdo con la clave de name de la primera matriz
  3. Utilice la permutación para reordenar ambas matrices

Ejemplo: digamos que la primera matriz es {"quick", "brown", "fox"}. La permutación comienza como {0, 1, 2}, y se convierte en {1, 2, 0} después del ordenamiento. Ahora puede ir a través de la matriz de permutación y volver a ordenar la matriz original y la segunda matriz según sea necesario.

NSArray *first = [NSArray arrayWithObjects: @"quick", @"brown", @"fox", @"jumps", nil]; 
NSArray *second = [NSArray arrayWithObjects: @"jack", @"loves", @"my", @"sphinx", nil]; 
NSMutableArray *p = [NSMutableArray arrayWithCapacity:first.count]; 
for (NSUInteger i = 0 ; i != first.count ; i++) { 
    [p addObject:[NSNumber numberWithInteger:i]]; 
} 
[p sortWithOptions:0 usingComparator:^NSComparisonResult(id obj1, id obj2) { 
    // Modify this to use [first objectAtIndex:[obj1 intValue]].name property 
    NSString *lhs = [first objectAtIndex:[obj1 intValue]]; 
    // Same goes for the next line: use the name 
    NSString *rhs = [first objectAtIndex:[obj2 intValue]]; 
    return [lhs compare:rhs]; 
}]; 
NSMutableArray *sortedFirst = [NSMutableArray arrayWithCapacity:first.count]; 
NSMutableArray *sortedSecond = [NSMutableArray arrayWithCapacity:first.count]; 
[p enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 
    NSUInteger pos = [obj intValue]; 
    [sortedFirst addObject:[first objectAtIndex:pos]]; 
    [sortedSecond addObject:[second objectAtIndex:pos]]; 
}]; 
NSLog(@"%@", sortedFirst); 
NSLog(@"%@", sortedSecond); 
+1

Excelente script. Ojalá fuera más simple, pero supongo que así es como es la programación ... –

3

Probablemente se podría hacer esto mediante el seguimiento de los índices de los objetos antes y después de la clasificación, pero tal vez sería más fácil tener un solo objeto que Hass todas estas propiedades

Person : NSObject 

@property (nonatomic, copy) NSString *name; 
@property (nonatomic, copy) NSString *addresss; 

A continuación, almacenar estos objetos en una única matriz que puede ordenar por name, o address rutas clave

4

La mejor manera es reestructurar sus datos para que solo tenga una matriz. En su ejemplo, tendría más sentido crear una nueva clase con el nombre y la dirección, colocarlos en una matriz y ordenarlos por su nombre.

+0

O simplemente cree una matriz de diccionarios, cada uno de los cuales contiene un nombre y la dirección correspondiente. – Caleb

+2

Es cierto, aunque los diccionarios siempre me dejan con la sensación de que a alguien no le importa lo suficiente sobre el propósito de sus datos para categorizarlo bien. :-) –

10

En primer lugar, es posible que desee volver a considerar una arquitectura que requiere que ordene dos matrices de forma paralela como esta. Pero una vez dicho esto, puede hacerlo creando una matriz temporal de diccionarios que mantienen emparejados los elementos de las dos matrices.

A continuación, ordenar la matriz combinada, y extraer las dos matrices de nuevo, ordenados conforme a lo solicitado:

de datos original:

NSArray *names  = @[@"Joe", @"Anna", @"Michael"]; 
NSArray *addresses = @[@"Hollywood bld", @"Some street 3", @"That other street"]; 

El código de clasificación real:

NSMutableArray *combined = [NSMutableArray array]; 

for (NSUInteger i = 0; i < names.count; i++) { 
    [combined addObject: @{@"name" : names[i], @"address": addresses[i]}]; 
} 

[combined sortUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]]]; 

names  = [combined valueForKey:@"name"]; 
addresses = [combined valueForKey:@"address"]; 

en cuenta que una valueForKey: utilizado en una matriz extrae una nueva matriz con el mismo tamaño, con las propiedades de los objetos en la matriz original. En este caso, crea nuevas matrices de las originales, ordenadas como deseadas.

Este enfoque solo requiere unas pocas líneas de código y es fácil de seguir y depurar, si es necesario.

+0

Buen uso de '-valueForKey:'. – jrc

Cuestiones relacionadas