Frage

Ich brauche meine NSArray rückgängig zu machen.

Als Beispiel:

[1,2,3,4,5] muss werden: [5,4,3,2,1]

Was ist der beste Weg, um dies zu erreichen?

War es hilfreich?

Lösung

Für eine umgekehrte Kopie eines Arrays zu erhalten, suchen Sie unter danielpunkass' Lösung reverseObjectEnumerator verwendet wird.

Für eine änderbare Array Umkehren können Sie die folgende Kategorie zu Ihrem Code hinzu:

@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

Andere Tipps

Es gibt eine viel einfachere Lösung, wenn Sie die Vorteile der integrierten in reverseObjectEnumerator Verfahren auf NSArray nehmen und die allObjects Methode des NSEnumerator:

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

allObjects dokumentiert als ein Array mit der Rückkehr die Objekte, die noch nicht mit nextObject durchlaufen haben, in dieser Reihenfolge:

  

Dieses Array enthält alle verbleibenden Objekte des Enumerators in aufgezählt, um .

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 eine 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. sortedArrayUsingComparator

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] der klare Sieger ist, wenn es darum geht, zu beschleunigen und Leichtigkeit.

DasBoot hat den richtigen Ansatz, aber es gibt ein paar Fehler in seinem Code. Hier ist ein vollständig generischer Code-Schnipsel, die jede NSMutableArray an Ort und Stelle umkehren werden:

/* 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, dass wickeln in einer C-Funktion, oder für Bonuspunkte, Nutzungskategorien es zu NSMutableArray hinzuzufügen. (In diesem Fall ‚Array‘ würde ‚Selbst‘.) Sie können auch durch die Zuordnung optimieren [array count] einer Variablen vor der Schleife und die Verwendung dieser Variable, wenn Sie es wünschen.

Wenn Sie nur eine regelmäßige NSArray haben, gibt es keine Möglichkeit, es an Ort und Stelle zu umkehren, weil NSArrays nicht geändert werden kann. Aber man kann eine umgekehrte Kopie machen:

NSMutableArray * copy = [NSMutableArray arrayWithCapacity:[array count]];

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

oder diesen kleinen Trick verwendet es in einer Zeile zu tun:

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

Wenn Sie nur eine Schleife wollen über ein Array zurück, können Sie eine for / in Schleife mit [array reverseObjectEnumerator] verwenden, aber es ist wahrscheinlich ein bisschen effizienter -enumerateObjectsWithOptions:usingBlock: zu verwenden:

[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 Wesentlichen im Jahr 2014 aktualisiert mit fünf Jahren der Stiftung Erfahrung, eine neuen Objective-C-Funktion oder zwei, und ein paar Tipps von den Kommentaren)

Nach dem anderen Antworten über die Überprüfung und die Suche nach Matt Gallagher Diskussion hier

Ich schlage vor, diese:

NSMutableArray * reverseArray = [NSMutableArray arrayWithCapacity:[myArray count]]; 

for (id element in [myArray reverseObjectEnumerator]) {
    [reverseArray addObject:element];
}

Wie Matt beobachtet:

  

Im obigen Fall können Sie, wenn sich fragen - [NSArray reverseObjectEnumerator] bei jeder Iteration der Schleife ausgeführt werden würde - möglicherweise den Code zu verlangsamen. <...>

Kurz darauf antwortet er so:

  

<...> Der „Sammlung“ Ausdruck wird nur einmal ausgewertet, wenn die for-Schleife beginnt. Dies ist der beste Fall, da Sie sicher eine teure Funktion in der „Sammlung“ Ausdruck ohne Auswirkungen auf die pro-Iteration Leistung der Schleife setzen können.

Georg Schölly Kategorien sind sehr schön. Doch für NSMutableArray, führt mit NSUIntegers für den Indizes in 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

Der effizienteste Weg, um ein Array in umgekehrten aufzuzählen:

Mit enumerateObjectsWithOptions:NSEnumerationReverse usingBlock. Mit @ oben JohannesFahrenkrug Benchmark schloß dieser 8x schneller 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];
}

Reverse-Array und Looping durch:

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

Um dies zu aktualisieren, in Swift kann es leicht gemacht werden:

array.reverse()

Was mich betrifft, haben Sie darüber nachgedacht, wie die Anordnung in erster Linie bevölkert war? Ich war in dem Prozess viele Objekte auf ein Array von Zugabe und entschied sich eine am Anfang einzufügen, alle vorhandenen Objekte, die von einem nach oben drücken. Erfordert einen änderbaren Array, in diesem Fall.

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 @[];
}

Ich weiß nicht, irgend in Verfahren gebaut. Aber mit der Hand Codierung ist nicht allzu schwierig. Unter der Annahme, die Elemente des Arrays Sie beschäftigen, sind NSNumber Objekte vom Typ Integer und ‚arr‘ wird die NSMutableArray, die Sie stornieren 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 dann haben Sie die änderbaren Array erstellen Sie zunächst mit dem Inhalt des ursprünglichen NSArray ( ‚origArray‘).

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

Edit:. Feste n -> n / 2 in der Schleifenzählung und geändert NSNumber auf die allgemeineren ID aufgrund der Vorschläge in Brent Antwort

Wenn alles, was Sie tun wollen Iterierte in umgekehrter Richtung ist, versuchen Sie dies:

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

Sie können die [myArrayCount] einmal tun und es zu einer lokalen Variablen speichern (ich glaube, es ist teuer), aber ich glaube auch, dass der Compiler so ziemlich die gleiche Sache mit dem Code zu tun, wie oben geschrieben.

Swift 3 Syntax:

let reversedArray = array.reversed()

Versuchen Sie folgendes:

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];
}

Es gibt eine einfache Möglichkeit, es 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.

Hier ist ein schönes Makro, das entweder für 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]];\
    }\
}

So verwenden Sie rufen Sie einfach an: reverseArray(myArray);

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top