Ich muss meine umkehren NSArray
.
Als Beispiel:
[1,2,3,4,5]
muss werden: [5,4,3,2,1]
Was ist der beste Weg, um dies zu erreichen?
Ich muss meine umkehren NSArray
.
Als Beispiel:
[1,2,3,4,5]
muss werden: [5,4,3,2,1]
Was ist der beste Weg, um dies zu erreichen?
Antworten:
Um eine umgekehrte Kopie eines Arrays zu erhalten, schauen Sie sich die Lösung von danielpunkass mit an reverseObjectEnumerator
.
Um ein veränderliches Array umzukehren, können Sie Ihrem Code die folgende Kategorie hinzufügen:
@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
Es gibt eine viel einfachere Lösung, wenn Sie die integrierte reverseObjectEnumerator
Methode nutzen NSArray
und die allObjects
Methode NSEnumerator
:
NSArray* reversedArray = [[startArray reverseObjectEnumerator] allObjects];
allObjects
Es wird dokumentiert , dass ein Array mit den Objekten zurückgegeben wird, die noch nicht durchlaufen wurden nextObject
, und zwar in der folgenden Reihenfolge:
Dieses Array enthält alle verbleibenden Objekte des Enumerators in aufgezählter Reihenfolge .
Einige Benchmarks
1. reverseObjectEnumerator allObjects
Dies ist die schnellste Methode:
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);
Ergebnis: executionTime = 0.000026
2. Iterieren über einen reverseObjectEnumerator
Dies ist zwischen 1,5x und 2,5x langsamer:
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);
Ergebnis: executionTime = 0.000071
3. sortierterArrayUsingComparator
Dies ist zwischen 30x und 40x langsamer (keine Überraschungen hier):
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);
Ergebnis: executionTime = 0.001100
So [[anArray reverseObjectEnumerator] allObjects]
ist der klare Gewinner, wenn es um Geschwindigkeit und Leichtigkeit geht.
enumerateObjectsWithOptions:NSEnumerationReverse
?
enumerateObjectsWithOptions:NSEnumerationReverse
- den obersten in 0.000072
Sekunden, die Blockmethode in 0.000009
Sekunden.
DasBoot hat den richtigen Ansatz, aber sein Code enthält einige Fehler. Hier ist ein vollständig generisches Code-Snippet, das alle vorhandenen NSMutableArray umkehrt:
/* 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];
}
Sie können dies in eine C-Funktion einschließen oder für Bonuspunkte Kategorien verwenden, um es zu NSMutableArray hinzuzufügen. (In diesem Fall wird 'array' zu 'self'.) Sie können es auch optimieren, indem Sie [array count]
einer Variablen vor der Schleife zuweisen und diese Variable verwenden, wenn Sie dies wünschen.
Wenn Sie nur ein reguläres NSArray haben, können Sie es nicht umkehren, da NSArrays nicht geändert werden können. Sie können jedoch eine umgekehrte Kopie erstellen:
NSMutableArray * copy = [NSMutableArray arrayWithCapacity:[array count]];
for(int i = 0; i < [array count]; i++) {
[copy addObject:[array objectAtIndex:[array count] - i - 1]];
}
Oder verwenden Sie diesen kleinen Trick, um es in einer Zeile zu tun:
NSArray * copy = [[array reverseObjectEnumerator] allObjects];
Wenn Sie ein Array nur rückwärts durchlaufen möchten, können Sie eine for
/ in
-Schleife mit verwenden [array reverseObjectEnumerator]
, die Verwendung ist jedoch wahrscheinlich etwas effizienter -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.)
}];
( Hinweis : Im Jahr 2014 mit fünf weiteren Jahren Foundation-Erfahrung, ein oder zwei neuen Objective-C-Funktionen und einigen Tipps aus den Kommentaren erheblich aktualisiert.)
Nachdem Sie die Antworten des anderen oben überprüft und Matt Gallaghers Diskussion hier gefunden haben
Ich schlage vor:
NSMutableArray * reverseArray = [NSMutableArray arrayWithCapacity:[myArray count]];
for (id element in [myArray reverseObjectEnumerator]) {
[reverseArray addObject:element];
}
Wie Matt bemerkt:
Im obigen Fall fragen Sie sich möglicherweise, ob - [NSArray reverseObjectEnumerator] bei jeder Iteration der Schleife ausgeführt wird - was möglicherweise den Code verlangsamt. <...>
Kurz darauf antwortet er folgendermaßen:
<...> Der Ausdruck "Sammlung" wird nur einmal ausgewertet, wenn die for-Schleife beginnt. Dies ist der beste Fall, da Sie eine teure Funktion sicher in den Ausdruck "Sammlung" einfügen können, ohne die Leistung der Schleife pro Iteration zu beeinträchtigen.
Georg Schöllys Kategorien sind sehr schön. Bei NSMutableArray führt die Verwendung von NSUIntegern für die Indizes jedoch zu einem Absturz, wenn das Array leer ist. Der richtige Code lautet:
@implementation NSMutableArray (Reverse)
- (void)reverse {
NSInteger i = 0;
NSInteger j = [self count] - 1;
while (i < j) {
[self exchangeObjectAtIndex:i
withObjectAtIndex:j];
i++;
j--;
}
}
@end
Verwenden Sie enumerateObjectsWithOptions:NSEnumerationReverse usingBlock
. Mit dem obigen Benchmark von @ JohannesFahrenkrug wurde dies 8x schneller abgeschlossen als [[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);
NSMutableArray *objMyObject = [NSMutableArray arrayWithArray:[self reverseArray:objArrayToBeReversed]];
// Function reverseArray
-(NSArray *) reverseArray : (NSArray *) myArray {
return [[myArray reverseObjectEnumerator] allObjects];
}
Array umkehren und durchlaufen:
[[[startArray reverseObjectEnumerator] allObjects] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
...
}];
Haben Sie sich überlegt, wie das Array überhaupt gefüllt wurde? Ich war gerade dabei, einem Array VIELE Objekte hinzuzufügen, und entschied mich, jedes am Anfang einzufügen und alle vorhandenen Objekte um eins nach oben zu verschieben. Erfordert in diesem Fall ein veränderbares Array.
NSMutableArray *myMutableArray = [[NSMutableArray alloc] initWithCapacity:1];
[myMutableArray insertObject:aNewObject atIndex:0];
Oder der Scala-Weg:
-(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 @[];
}
Es gibt einen einfachen Weg, dies zu tun.
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"]
Ich hoffe das hilft.
Ich kenne keine eingebaute Methode. Das Codieren von Hand ist jedoch nicht allzu schwierig. Angenommen, die Elemente des Arrays, mit denen Sie sich befassen, sind NSNumber-Objekte vom Typ Integer, und 'arr' ist das NSMutableArray, das Sie umkehren möchten.
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];
}
Da Sie mit einem NSArray beginnen, müssen Sie zuerst das veränderbare Array mit dem Inhalt des ursprünglichen NSArray ('origArray') erstellen.
NSMutableArray * arr = [[NSMutableArray alloc] init];
[arr setArray:origArray];
Bearbeiten: n -> n / 2 in der Schleifenzahl behoben und NSNumber aufgrund der Vorschläge in Brents Antwort in die allgemeinere ID geändert.
Wenn Sie nur in umgekehrter Reihenfolge iterieren möchten, versuchen Sie Folgendes:
// iterate backwards
nextIndex = (currentIndex == 0) ? [myArray count] - 1 : (currentIndex - 1) % [myArray count];
Sie können [myArrayCount] einmal ausführen und in einer lokalen Variablen speichern (ich denke, es ist teuer), aber ich vermute auch, dass der Compiler mit dem oben beschriebenen Code so ziemlich dasselbe tun wird.
Versuche dies:
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];
}
Hier ist ein schönes Makro , das für beide NSMutableArray arbeiten ODER 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]];\
}\
}
Um zu verwenden, rufen Sie einfach an: reverseArray(myArray);