如何在 Objective-C 中反转 NSArray?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/586370/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 21:11:06  来源:igfitidea点击:

How can I reverse a NSArray in Objective-C?

objective-cnsarray

提问by Andy Jacobs

I need to reverse my NSArray.

我需要反转我的NSArray.

As an example:

举个例子:

[1,2,3,4,5]must become: [5,4,3,2,1]

[1,2,3,4,5]必须变成: [5,4,3,2,1]

What is the best way to achieve this?

实现这一目标的最佳方法是什么?

采纳答案by Georg Sch?lly

For obtaining a reversed copy of an array, look at danielpunkass' solutionusing reverseObjectEnumerator.

为了得到阵列的相反副本,看看danielpunkass'溶液使用reverseObjectEnumerator

For reversing a mutable array, you can add the following category to your code:

要反转可变数组,您可以将以下类别添加到您的代码中:

@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

回答by danielpunkass

There is a much easier solution, if you take advantage of the built-in reverseObjectEnumeratormethod on NSArray, and the allObjectsmethod of NSEnumerator:

如果您利用reverseObjectEnumeratoron的内置方法NSArray和 的allObjects方法,则有一个更简单的解决方案NSEnumerator

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

allObjectsis documentedas returning an array with the objects that have not yet been traversed with nextObject, in order:

allObjects记录为返回一个数组,其中包含尚未遍历的对象nextObject,按顺序:

This array contains all the remaining objects of the enumerator in enumerated order.

该数组以枚举顺序包含枚举器的所有剩余对象。

回答by Johannes Fahrenkrug

Some benchmarks

一些基准

1. reverseObjectEnumerator allObjects

1. reverseObjectEnumerator allObjects

This is the fastest method:

这是最快的方法:

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);

Result: executionTime = 0.000026

结果: executionTime = 0.000026

2. Iterating over an reverseObjectEnumerator

2. 迭代一个 reverseObjectEnumerator

This is between 1.5x and 2.5x slower:

这慢了 1.5 倍到 2.5 倍:

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);

Result: executionTime = 0.000071

结果: executionTime = 0.000071

3. sortedArrayUsingComparator

3. sortedArrayUsingComparator

This is between 30x and 40x slower (no surprises here):

这慢了 30 到 40 倍(这里没有意外):

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);

Result: executionTime = 0.001100

结果: executionTime = 0.001100

So [[anArray reverseObjectEnumerator] allObjects]is the clear winner when it comes to speed and ease.

[[anArray reverseObjectEnumerator] allObjects]在速度和易用性方面,明显的赢家也是如此。

回答by Brent Royal-Gordon

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:

DasBoot 有正确的方法,但他的代码中有一些错误。这是一个完全通用的代码片段,可以在适当的位置反转任何 NSMutableArray:

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

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'.) You can also optimize it by assigning [array count]to a variable before the loop and using that variable, if you desire.

您可以将其包装在 C 函数中,或者为了获得奖励积分,使用类别将其添加到 NSMutableArray。(在这种情况下,'array' 将变成 'self'。)如果需要,您还可以通过[array count]在循环之前分配给变量并使用该变量来优化它。

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:

如果你只有一个普通的 NSArray,就没有办法在原地反转它,因为 NSArrays 不能被修改。但是您可以进行反向复制:

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

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

Or use this little trick to do it in one line:

或者使用这个小技巧在一行中完成:

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

If you just want to loop over an array backwards, you can use a for/inloop with [array reverseObjectEnumerator], but it's likely a bit more efficient to use -enumerateObjectsWithOptions:usingBlock::

如果您只想向后遍历数组,则可以将for/in循环与 一起使用[array reverseObjectEnumerator],但使用 可能会更有效一些-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.)
}];

(Note: Substantially updated in 2014 with five more years of Foundation experience, a new Objective-C feature or two, and a couple tips from the comments.)

注意:在 2014 年进行了实质性更新,拥有五年以上的 Foundation 经验、一两个新的 Objective-C 功能以及评论中的一些提示。)

回答by Aeronin

After reviewing the other's answers above and finding Matt Gallagher's discussion here

在查看上述其他人的答案并在此处找到Matt Gallagher 的讨论后

I propose this:

我提出这个:

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

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

As Matt observes:

正如马特所观察到的:

In the above case, you may wonder if -[NSArray reverseObjectEnumerator] would be run on every iteration of the loop — potentially slowing down the code. <...>

在上述情况下,您可能想知道 -[NSArray reverseObjectEnumerator] 是否会在循环的每次迭代中运行——可能会减慢代码速度。<...>

Shortly thereafter, he answers thus:

不久之后,他是这样回答的:

<...> The "collection" expression is only evaluated once, when the for loop begins. This is the best case, since you can safely put an expensive function in the "collection" expression without impacting upon the per-iteration performance of the loop.

<...> 当 for 循环开始时,“collection”表达式只计算一次。这是最好的情况,因为您可以安全地将昂贵的函数放入“集合”表达式中,而不会影响循环的每次迭代性能。

回答by Werner Jainek

Georg Sch?lly's categories are very nice. However, for NSMutableArray, using NSUIntegers for the indices results in a crash when the array is empty. The correct code is:

Georg Sch?lly 的分类非常好。然而,对于 NSMutableArray,当数组为空时,使用 NSUIntegers 作为索引会导致崩溃。正确的代码是:

@implementation NSMutableArray (Reverse)

- (void)reverse {
    NSInteger i = 0;
    NSInteger j = [self count] - 1;
    while (i < j) {
        [self exchangeObjectAtIndex:i
                  withObjectAtIndex:j];

        i++;
        j--;
    }
}

@end

回答by brandonscript

The most efficient way to enumerate an array in reverse:

反向枚举数组的最有效方法:

Use enumerateObjectsWithOptions:NSEnumerationReverse usingBlock. Using @JohannesFahrenkrug's benchmark above, this completed 8x quicker than [[array reverseObjectEnumerator] allObjects];:

使用enumerateObjectsWithOptions:NSEnumerationReverse usingBlock. 使用上面@JohannesFahrenkrug 的基准测试,它的完成速度比[[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);

回答by Jayprakash Dubey

NSMutableArray *objMyObject = [NSMutableArray arrayWithArray:[self reverseArray:objArrayToBeReversed]];

// Function reverseArray 
-(NSArray *) reverseArray : (NSArray *) myArray {   
    return [[myArray reverseObjectEnumerator] allObjects];
}

回答by Aqib Mumtaz

Reverse array and looping through it:

反转数组并循环遍历它:

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

回答by Julio

To update this, in Swift it can be done easily with:

要更新它,在 Swift 中可以通过以下方式轻松完成:

array.reverse()