objective arreglos array objective-c nsarray

objective-c - arreglos - nsdictionary objective c



¿Cómo puedo revertir una NSArray en Objective-C? (18)

Necesito revertir mi NSArray .

Como ejemplo:

[1,2,3,4,5] debe convertirse en: [5,4,3,2,1]

¿Cuál es la mejor manera de lograr esto?


La forma más eficiente de enumerar una matriz a la inversa:

Use enumerateObjectsWithOptions:NSEnumerationReverse usingBlock . Usando el punto de referencia de @ JohannesFahrenkrug arriba, esto se completó 8 veces más rápido que [[array reverseObjectEnumerator] allObjects]; :

NSDate *methodStart = [NSDate date]; [anArray enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) { // }]; NSDate *methodFinish = [NSDate date]; NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart]; NSLog(@"executionTime = %f", executionTime);


Aquí hay una buena macro que funcionará para NSMutableArray O NSArray:

#define reverseArray(__theArray) {/ if ([__theArray isKindOfClass:[NSMutableArray class]]) {/ if ([(NSMutableArray *)__theArray count] > 1) {/ NSUInteger i = 0;/ NSUInteger j = [(NSMutableArray *)__theArray count]-1;/ while (i < j) {/ [(NSMutableArray *)__theArray exchangeObjectAtIndex:i/ withObjectAtIndex:j];/ i++;/ j--;/ }/ }/ } else if ([__theArray isKindOfClass:[NSArray class]]) {/ __theArray = [[NSArray alloc] initWithArray:[[(NSArray *)__theArray reverseObjectEnumerator] allObjects]];/ }/ }

Para usar solo llamar: reverseArray(myArray);


DasBoot tiene el enfoque correcto, pero hay algunos errores en su código. Aquí hay un fragmento de código completamente genérico que revertirá cualquier NSMutableArray en su lugar:

/* Algorithm: swap the object N elements from the top with the object N * elements from the bottom. Integer division will wrap down, leaving * the middle element untouched if count is odd. */ for(int i = 0; i < [array count] / 2; i++) { int j = [array count] - i - 1; [array exchangeObjectAtIndex:i withObjectAtIndex:j]; }

Puede envolver eso en una función C, o para obtener puntos de bonificación, use categorías para agregarlo a NSMutableArray. (En ese caso, ''array'' se convertiría en ''self''). También puede optimizarlo asignando [array count] a una variable antes del bucle y usando esa variable, si lo desea.

Si solo tiene un NSArray normal, no hay manera de revertirlo en su lugar, porque los NSArrays no se pueden modificar. Pero puedes hacer una copia invertida:

NSMutableArray * copy = [NSMutableArray arrayWithCapacity:[array count]]; for(int i = 0; i < [array count]; i++) { [copy addObject:[array objectAtIndex:[array count] - i - 1]]; }

O usa este pequeño truco para hacerlo en una línea:

NSArray * copy = [[array reverseObjectEnumerator] allObjects];

Si solo desea hacer un bucle en una matriz hacia atrás, puede usar un bucle for / in con [array reverseObjectEnumerator] , pero es probable que sea un poco más eficiente usar -enumerateObjectsWithOptions:usingBlock: ::

[array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) { // This is your loop body. Use the object in obj here. // If you need the index, it''s in idx. // (This is the best feature of this method, IMHO.) // Instead of using ''continue'', use ''return''. // Instead of using ''break'', set ''*stop = YES'' and then ''return''. // Making the surrounding method/block return is tricky and probably // requires a ''__block'' variable. // (This is the worst feature of this method, IMHO.) }];

( Nota : Substancialmente actualizado en 2014 con cinco años más de experiencia en la Fundación, una nueva característica de Objective-C o dos, y un par de consejos de los comentarios).


Después de revisar las respuestas del otro y encontrar la discusión de Matt Gallagher aquí

Propongo esto:

NSMutableArray * reverseArray = [NSMutableArray arrayWithCapacity:[myArray count]]; for (id element in [myArray reverseObjectEnumerator]) { [reverseArray addObject:element]; }

Como Matt observa:

En el caso anterior, puede preguntarse si: [NSArray reverseObjectEnumerator] se ejecutaría en cada iteración del bucle, lo que podría ralentizar el código. <...>

Poco después, responde así:

<...> La expresión "colección" solo se evalúa una vez, cuando comienza el bucle for. Este es el mejor de los casos, ya que puede colocar de forma segura una función costosa en la expresión "colección" sin afectar el rendimiento de iteración del bucle.


En cuanto a mí, ¿has considerado cómo se llenó la matriz en primer lugar? Estaba en el proceso de agregar MUCHOS objetos a una matriz, y decidí insertar cada uno al principio, empujando cualquier objeto existente hacia arriba en uno. Requiere una matriz mutable, en este caso.

NSMutableArray *myMutableArray = [[NSMutableArray alloc] initWithCapacity:1]; [myMutableArray insertObject:aNewObject atIndex:0];


Hay una manera fácil de hacerlo.

NSArray *myArray = @[@"5",@"4",@"3",@"2",@"1"]; NSMutableArray *myNewArray = [[NSMutableArray alloc] init]; //this object is going to be your new array with inverse order. for(int i=0; i<[myNewArray count]; i++){ [myNewArray insertObject:[myNewArray objectAtIndex:i] atIndex:0]; } //other way to do it for(NSString *eachValue in myArray){ [myNewArray insertObject:eachValue atIndex:0]; } //in both cases your new array will look like this NSLog(@"myNewArray: %@", myNewArray); //[@"1",@"2",@"3",@"4",@"5"]

Espero que esto ayude.


Hay una solución mucho más fácil, si aprovecha el método reverseObjectEnumerator en NSArray , y el método NSEnumerator de NSEnumerator :

NSArray* reversedArray = [[startArray reverseObjectEnumerator] allObjects];

allObjects está documentado como que devuelve una matriz con los objetos que aún no se han atravesado con nextObject , en orden:

Esta matriz contiene todos los objetos restantes del enumerador en orden enumerado .


Invertir la matriz y en bucle a través de él:

[[[startArray reverseObjectEnumerator] allObjects] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { ... }];


Las categorías de Georg Schölly son muy bonitas. Sin embargo, para NSMutableArray, el uso de NSUIntegers para los índices provoca un bloqueo cuando la matriz está vacía. El código correcto es:

@implementation NSMutableArray (Reverse) - (void)reverse { NSInteger i = 0; NSInteger j = [self count] - 1; while (i < j) { [self exchangeObjectAtIndex:i withObjectAtIndex:j]; i++; j--; } } @end


No conozco ningún método incorporado. Pero, la codificación a mano no es demasiado difícil. Suponiendo que los elementos de la matriz con la que está tratando son objetos NSNumber de tipo entero, y ''arr'' es el NSMutableArray que desea revertir.

int n = [arr count]; for (int i=0; i<n/2; ++i) { id c = [[arr objectAtIndex:i] retain]; [arr replaceObjectAtIndex:i withObject:[arr objectAtIndex:n-i-1]]; [arr replaceObjectAtIndex:n-i-1 withObject:c]; }

Como comienza con una NSArray, primero debe crear la matriz mutable con el contenido de la NSArray original (''origArray'').

NSMutableArray * arr = [[NSMutableArray alloc] init]; [arr setArray:origArray];

Edición: Se corrigió n -> n / 2 en el conteo de bucles y se cambió el número de NS a la identificación más genérica debido a las sugerencias en la respuesta de Brent.


O el camino de Scala:

-(NSArray *)reverse { if ( self.count < 2 ) return self; else return [[self.tail reverse] concat:[NSArray arrayWithObject:self.head]]; } -(id)head { return self.firstObject; } -(NSArray *)tail { if ( self.count > 1 ) return [self subarrayWithRange:NSMakeRange(1, self.count - 1)]; else return @[]; }


Para actualizar esto, en Swift se puede hacer fácilmente con:

array.reverse()


Para obtener una copia invertida de una matriz, vea la solución de reverseObjectEnumerator usando reverseObjectEnumerator .

Para revertir una matriz mutable, puede agregar la siguiente categoría a su código:

@implementation NSMutableArray (Reverse) - (void)reverse { if ([self count] <= 1) return; NSUInteger i = 0; NSUInteger j = [self count] - 1; while (i < j) { [self exchangeObjectAtIndex:i withObjectAtIndex:j]; i++; j--; } } @end


Prueba esto:

for (int i = 0; i < [arr count]; i++) { NSString *str1 = [arr objectAtIndex:[arr count]-1]; [arr insertObject:str1 atIndex:i]; [arr removeObjectAtIndex:[arr count]-1]; }


Si todo lo que quieres hacer es iterar a la inversa, prueba esto:

// iterate backwards nextIndex = (currentIndex == 0) ? [myArray count] - 1 : (currentIndex - 1) % [myArray count];

Puedes hacer el [myArrayCount] una vez y guardarlo en una variable local (creo que es caro), pero también creo que el compilador hará prácticamente lo mismo con el código escrito arriba.


Sintaxis de Swift 3:

let reversedArray = array.reversed()


Algunos puntos de referencia

1. reverseObjectEnumerator allObjects

Este es el método más rápido:

NSArray *anArray = @[@"aa", @"ab", @"ac", @"ad", @"ae", @"af", @"ag", @"ah", @"ai", @"aj", @"ak", @"al", @"am", @"an", @"ao", @"ap", @"aq", @"ar", @"as", @"at", @"au", @"av", @"aw", @"ax", @"ay", @"az", @"ba", @"bb", @"bc", @"bd", @"bf", @"bg", @"bh", @"bi", @"bj", @"bk", @"bl", @"bm", @"bn", @"bo", @"bp", @"bq", @"br", @"bs", @"bt", @"bu", @"bv", @"bw", @"bx", @"by", @"bz", @"ca", @"cb", @"cc", @"cd", @"ce", @"cf", @"cg", @"ch", @"ci", @"cj", @"ck", @"cl", @"cm", @"cn", @"co", @"cp", @"cq", @"cr", @"cs", @"ct", @"cu", @"cv", @"cw", @"cx", @"cy", @"cz"]; NSDate *methodStart = [NSDate date]; NSArray *reversed = [[anArray reverseObjectEnumerator] allObjects]; NSDate *methodFinish = [NSDate date]; NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart]; NSLog(@"executionTime = %f", executionTime);

Resultado : executionTime = 0.000026

2. Iterando sobre un reverseObjectEnumerator

Esto es entre 1.5x y 2.5x más lento:

NSDate *methodStart = [NSDate date]; NSMutableArray *array = [NSMutableArray arrayWithCapacity:[anArray count]]; NSEnumerator *enumerator = [anArray reverseObjectEnumerator]; for (id element in enumerator) { [array addObject:element]; } NSDate *methodFinish = [NSDate date]; NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart]; NSLog(@"executionTime = %f", executionTime);

Resultado : executionTime = 0.000071

3. sortedArrayUsingComparator

Esto es entre 30x y 40x más lento (sin sorpresas aquí):

NSDate *methodStart = [NSDate date]; NSArray *reversed = [anArray sortedArrayUsingComparator: ^(id obj1, id obj2) { return [anArray indexOfObject:obj1] < [anArray indexOfObject:obj2] ? NSOrderedDescending : NSOrderedAscending; }]; NSDate *methodFinish = [NSDate date]; NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart]; NSLog(@"executionTime = %f", executionTime);

Resultado : executionTime = 0.001100

Así que [[anArray reverseObjectEnumerator] allObjects] es el claro ganador cuando se trata de velocidad y facilidad.


NSMutableArray *objMyObject = [NSMutableArray arrayWithArray:[self reverseArray:objArrayToBeReversed]]; // Function reverseArray -(NSArray *) reverseArray : (NSArray *) myArray { return [[myArray reverseObjectEnumerator] allObjects]; }