I need to reverse my NSArray.
As an example:
[1,2,3,4,5] must become [5,4,3,2,1]
What is the best way to achieve this?
I need to reverse my NSArray.
As an example:
[1,2,3,4,5] must become [5,4,3,2,1]
What is the best way to achieve this?
I don't know of any built in method. But, coding by hand is not too difficult. Assuming the elements of the array you are dealing with are NSNumber objects of integer type, and 'arr' is the NSMutableArray that you want to reverse.
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];
}
Since you start with a NSArray then you have to create the mutable array first with the contents of the original NSArray ('origArray').
NSMutableArray * arr = [[NSMutableArray alloc] init];
[arr setArray:origArray];
Edit: Fixed n -> n/2 in the loop count and changed NSNumber to the more generic id due to the suggestions in Brent's answer.
DasBoot has the right approach, but there are a few mistakes in his code. Here's a completely generic code snippet that will reverse any NSMutableArray in place:
/* 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 intact if count is odd
*/
for(int i = 0; i < [array count] / 2; i++) {
int j = [array count] - i - 1;
id temp = [[array objectAtIndex:i] retain];
[array replaceObjectAtIndex:i withObject:[array objectAtIndex:j]];
[array replaceObjectAtIndex:j withObject:temp];
[temp release];
}
You can wrap that in a C function, or for bonus points, use categories to add it to NSMutableArray. (In that case, 'array' would become 'self'.)
If you only have a regular NSArray, there's no way to reverse it in place, because NSArrays cannot be modified. But you can make a reversed copy:
NSMutableArray * copy = [NSMutableArray arrayWithCapacity:[array count]];
for(int i = 0; i < [array count]; i++) {
[copy addObject:[array objectAtIndex:[array count] - i - 1]];
}
@implementation NSArray (Reverse)
- (NSArray *)reversedArray {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:[self count]];
NSEnumerator *enumerator = [self reverseObjectEnumerator];
for (id element in enumerator) {
[array addObject:element];
}
return array;
}
@end
@implementation NSMutableArray (Reverse)
- (void)reverse {
NSUInteger i = 0;
NSUInteger j = [self count] - 1;
while (i < j) {
[self exchangeObjectAtIndex:i
withObjectAtIndex:j];
i++;
j--;
}
}
@end
There is a much easier solution, if you take advantage of the built-in reverseObjectEnumerator
method on NSArray
, and the allObjects
method of NSEnumerator
:
NSArray* reversedArray = [[startArray reverseObjectEnumerator] allObjects];
Because allObjects
is documented as returning an array with the objects that have not yet been traversed with nextObject
, it strongly implies that those objects will be delivered in order of the enumerator. It even points out that after calling allObjects
, the next object on the enumerator will be nil
.
It's also worth looking at this: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Collections/Articles/sortingFilteringArrays.html which tells you how to sort an array in reverse order (which is commonly what you are doing, for instance in using an array derived from NSDictionary#allKeys, and you want reverse date/alpha order to serve as grouping for UITable on iPhone, etc).
Don't use danielpunkass's solution. I used it thinking it was a great shortcut, but now I've just spent 3 hours trying to figure out why my A* algorithm was broken. It's because it returns the wrong set!