Tôi cần phải đảo ngược của tôi NSArray
.
Ví dụ:
[1,2,3,4,5]
phải trở thành: [5,4,3,2,1]
cách tốt nhất để đạt được điều này là gì?
Tôi cần phải đảo ngược của tôi NSArray
.
Ví dụ:
[1,2,3,4,5]
phải trở thành: [5,4,3,2,1]
cách tốt nhất để đạt được điều này là gì?
Câu trả lời:
Để có được một bản sao đảo ngược của một mảng, hãy xem giải pháp của danielpunkass bằng cách sử dụng reverseObjectEnumerator
.
Để đảo ngược một mảng có thể thay đổi, bạn có thể thêm danh mục sau vào mã của mình:
@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
Có một giải pháp dễ dàng hơn nhiều, nếu bạn tận dụng reverseObjectEnumerator
phương thức tích hợp sẵn NSArray
và allObjects
phương pháp NSEnumerator
:
NSArray* reversedArray = [[startArray reverseObjectEnumerator] allObjects];
allObjects
được ghi lại là trả về một mảng với các đối tượng chưa được duyệt qua nextObject
, theo thứ tự:
Mảng này chứa tất cả các đối tượng còn lại của điều tra theo thứ tự liệt kê .
Một số điểm chuẩn
1. ReverseObjectEnumerator allObjects
Đây là phương pháp nhanh nhất:
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);
Kết quả: executionTime = 0.000026
2. Lặp lại một ReverseObjectEnumerator
Tốc độ này chậm hơn từ 1,5 lần đến 2,5 lần:
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);
Kết quả: executionTime = 0.000071
3. sortArrayUsingComparator
Tốc độ này chậm hơn từ 30 lần đến 40 lần (không có gì ngạc nhiên ở đây):
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);
Kết quả: executionTime = 0.001100
Vì vậy, [[anArray reverseObjectEnumerator] allObjects]
là người chiến thắng rõ ràng khi nói đến tốc độ và dễ dàng.
enumerateObjectsWithOptions:NSEnumerationReverse
?
enumerateObjectsWithOptions:NSEnumerationReverse
- phương pháp hàng đầu hoàn thành trong 0.000072
vài giây, phương pháp khối tính bằng 0.000009
giây.
DasBoot có cách tiếp cận đúng, nhưng có một vài lỗi trong mã của anh ấy. Đây là một đoạn mã hoàn toàn chung chung sẽ đảo ngược mọi NSMutableArray tại chỗ:
/* 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];
}
Bạn có thể gói nó trong hàm C hoặc cho điểm thưởng, sử dụng các danh mục để thêm nó vào NSMutableArray. (Trong trường hợp đó, 'mảng' sẽ trở thành 'tự'.) Bạn cũng có thể tối ưu hóa nó bằng cách gán [array count]
cho một biến trước vòng lặp và sử dụng biến đó, nếu bạn muốn.
Nếu bạn chỉ có NSArray thông thường, không có cách nào để đảo ngược nó tại chỗ, bởi vì NSArrays không thể được sửa đổi. Nhưng bạn có thể tạo một bản sao đảo ngược:
NSMutableArray * copy = [NSMutableArray arrayWithCapacity:[array count]];
for(int i = 0; i < [array count]; i++) {
[copy addObject:[array objectAtIndex:[array count] - i - 1]];
}
Hoặc sử dụng mẹo nhỏ này để thực hiện trong một dòng:
NSArray * copy = [[array reverseObjectEnumerator] allObjects];
Nếu bạn chỉ muốn lặp lại một mảng ngược, bạn có thể sử dụng vòng lặp for
/ , nhưng có thể sử dụng hiệu quả hơn một chút :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.)
}];
( Lưu ý : Được cập nhật đáng kể vào năm 2014 với năm năm kinh nghiệm Foundation, tính năng Objective-C mới hoặc hai và một vài lời khuyên từ các nhận xét.)
Sau khi xem xét các câu trả lời của người khác ở trên và tìm thấy cuộc thảo luận của Matt Gallagher tại đây
Tôi đề xuất này:
NSMutableArray * reverseArray = [NSMutableArray arrayWithCapacity:[myArray count]];
for (id element in [myArray reverseObjectEnumerator]) {
[reverseArray addObject:element];
}
Như Matt quan sát:
Trong trường hợp trên, bạn có thể tự hỏi liệu - [NSArray ReverseObjectEnumerator] sẽ được chạy trên mỗi lần lặp của vòng lặp - có khả năng làm chậm mã. <...>
Ngay sau đó, anh trả lời:
<...> Biểu thức "bộ sưu tập" chỉ được đánh giá một lần, khi vòng lặp for bắt đầu. Đây là trường hợp tốt nhất, vì bạn có thể đặt một hàm đắt tiền trong biểu thức "bộ sưu tập" một cách an toàn mà không ảnh hưởng đến hiệu suất mỗi lần lặp của vòng lặp.
Thể loại của Georg Schölly rất đẹp. Tuy nhiên, đối với NSMutableArray, việc sử dụng NSUIntegers cho các chỉ số dẫn đến sự cố khi mảng trống. Mã chính xác là:
@implementation NSMutableArray (Reverse)
- (void)reverse {
NSInteger i = 0;
NSInteger j = [self count] - 1;
while (i < j) {
[self exchangeObjectAtIndex:i
withObjectAtIndex:j];
i++;
j--;
}
}
@end
Sử dụng enumerateObjectsWithOptions:NSEnumerationReverse usingBlock
. Sử dụng điểm chuẩn của @ JohannesFahrenkrug ở trên, việc này hoàn thành nhanh hơn 8 lần so với [[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];
}
Đảo ngược mảng và lặp qua nó:
[[[startArray reverseObjectEnumerator] allObjects] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
...
}];
Đối với tôi, bạn đã xem xét làm thế nào các mảng được phổ biến ở nơi đầu tiên? Tôi đang trong quá trình thêm NHIỀU đối tượng vào một mảng và quyết định chèn từng đối tượng vào lúc đầu, đẩy bất kỳ đối tượng hiện có nào lên một. Yêu cầu một mảng có thể thay đổi, trong trường hợp này.
NSMutableArray *myMutableArray = [[NSMutableArray alloc] initWithCapacity:1];
[myMutableArray insertObject:aNewObject atIndex:0];
Hoặc cách 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 @[];
}
Có một cách dễ dàng để làm điều đó.
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"]
Tôi hi vọng cái này giúp được.
Tôi không biết bất kỳ phương pháp được xây dựng trong. Nhưng, mã hóa bằng tay không quá khó. Giả sử các phần tử của mảng bạn đang xử lý là các đối tượng NSNumber có kiểu nguyên và 'mảng' là NSMutableArray mà bạn muốn đảo ngược.
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];
}
Vì bạn bắt đầu với NSArray nên trước tiên bạn phải tạo mảng có thể thay đổi với nội dung của NSArray gốc ('origArray').
NSMutableArray * arr = [[NSMutableArray alloc] init];
[arr setArray:origArray];
Chỉnh sửa: Đã sửa n -> n / 2 trong số vòng lặp và thay đổi NSNumber thành id chung hơn do các đề xuất trong câu trả lời của Brent.
Nếu tất cả những gì bạn muốn làm là lặp lại, hãy thử điều này:
// iterate backwards
nextIndex = (currentIndex == 0) ? [myArray count] - 1 : (currentIndex - 1) % [myArray count];
Bạn có thể thực hiện [myArrayCount] một lần và lưu nó vào một biến cục bộ (tôi nghĩ nó đắt tiền), nhưng tôi cũng đoán rằng trình biên dịch sẽ thực hiện tương tự với mã như được viết ở trên.
Đây là một macro đẹp sẽ hoạt động cho cả NSMutableArray HOẶC 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]];\
}\
}
Để sử dụng chỉ cần gọi: reverseArray(myArray);