Saya perlu membalikkan NSArray
.
Sebagai contoh:
[1,2,3,4,5]
harus menjadi: [5,4,3,2,1]
Apa cara terbaik untuk mencapai ini?
Saya perlu membalikkan NSArray
.
Sebagai contoh:
[1,2,3,4,5]
harus menjadi: [5,4,3,2,1]
Apa cara terbaik untuk mencapai ini?
Jawaban:
Untuk mendapatkan salinan array yang terbalik, lihat solusi danielpunkass menggunakan reverseObjectEnumerator
.
Untuk membalikkan array yang bisa berubah, Anda dapat menambahkan kategori berikut ke kode Anda:
@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
Ada solusi yang jauh lebih mudah, jika Anda memanfaatkan reverseObjectEnumerator
metode bawaan pada NSArray
, dan allObjects
metode NSEnumerator
:
NSArray* reversedArray = [[startArray reverseObjectEnumerator] allObjects];
allObjects
didokumentasikan sebagai mengembalikan array dengan objek yang belum dilalui nextObject
, dalam urutan:
Array ini berisi semua objek enumerator yang tersisa dalam urutan yang disebutkan .
Beberapa tolok ukur
1. reverseObjectEnumerator allObjects
Ini adalah metode tercepat:
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);
Hasil: executionTime = 0.000026
2. Iterating melalui reverseObjectEnumerator
Ini antara 1,5x dan 2,5x lebih lambat:
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);
Hasil: executionTime = 0.000071
3. DiurutkanArrayUsingComparator
Ini antara 30x dan 40x lebih lambat (tidak ada kejutan di sini):
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);
Hasil: executionTime = 0.001100
Jadi [[anArray reverseObjectEnumerator] allObjects]
adalah pemenang yang jelas dalam hal kecepatan dan kemudahan.
enumerateObjectsWithOptions:NSEnumerationReverse
?
enumerateObjectsWithOptions:NSEnumerationReverse
- yang teratas selesai dalam 0.000072
hitungan detik, metode blok dalam 0.000009
hitungan detik.
DasBoot memiliki pendekatan yang tepat, tetapi ada beberapa kesalahan dalam kodenya. Berikut cuplikan kode yang sepenuhnya generik yang akan membalikkan NSMutableArray apa pun di tempat:
/* 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];
}
Anda dapat membungkusnya dalam fungsi C, atau untuk poin bonus, gunakan kategori untuk menambahkannya ke NSMutableArray. (Dalam hal ini, 'array' akan menjadi 'mandiri'.) Anda juga dapat mengoptimalkannya dengan menetapkan [array count]
ke variabel sebelum loop dan menggunakan variabel itu, jika diinginkan.
Jika Anda hanya memiliki NSArray biasa, tidak ada cara untuk membalikkannya, karena NSArrays tidak dapat dimodifikasi. Tetapi Anda dapat membuat salinan terbalik:
NSMutableArray * copy = [NSMutableArray arrayWithCapacity:[array count]];
for(int i = 0; i < [array count]; i++) {
[copy addObject:[array objectAtIndex:[array count] - i - 1]];
}
Atau gunakan trik kecil ini untuk melakukannya dalam satu baris:
NSArray * copy = [[array reverseObjectEnumerator] allObjects];
Jika Anda hanya ingin mengulang array, Anda dapat menggunakan for
/ in
loop dengan [array reverseObjectEnumerator]
, tetapi sepertinya lebih efisien untuk digunakan -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.)
}];
( Catatan : Secara substansial diperbarui pada 2014 dengan pengalaman Foundation selama lima tahun lagi, satu atau dua fitur Objective-C baru, dan beberapa tips dari komentar.)
Setelah meninjau jawaban yang lain di atas dan menemukan diskusi Matt Gallagher di sini
Saya mengusulkan ini:
NSMutableArray * reverseArray = [NSMutableArray arrayWithCapacity:[myArray count]];
for (id element in [myArray reverseObjectEnumerator]) {
[reverseArray addObject:element];
}
Seperti yang diamati Matt:
Dalam kasus di atas, Anda mungkin bertanya-tanya apakah - [NSArray reverseObjectEnumerator] akan dijalankan pada setiap iterasi dari loop - berpotensi memperlambat kode. <...>
Segera setelah itu, ia menjawab sebagai berikut:
<...> Ekspresi "koleksi" hanya dievaluasi satu kali, ketika perulangan for dimulai. Ini adalah kasus terbaik, karena Anda dapat dengan aman memasukkan fungsi mahal dalam ekspresi "koleksi" tanpa memengaruhi kinerja perulangan dari loop.
Kategori Georg Schölly sangat bagus. Namun, untuk NSMutableArray, menggunakan NSUIntegers untuk indeks akan menghasilkan crash ketika array kosong. Kode yang benar adalah:
@implementation NSMutableArray (Reverse)
- (void)reverse {
NSInteger i = 0;
NSInteger j = [self count] - 1;
while (i < j) {
[self exchangeObjectAtIndex:i
withObjectAtIndex:j];
i++;
j--;
}
}
@end
Gunakan enumerateObjectsWithOptions:NSEnumerationReverse usingBlock
. Menggunakan patokan @ JohannesFahrenkrug di atas, ini menyelesaikan 8x lebih cepat dari [[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];
}
Membalikkan array dan mengulanginya:
[[[startArray reverseObjectEnumerator] allObjects] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
...
}];
Sedangkan untuk saya, sudahkah Anda mempertimbangkan bagaimana array dihuni di tempat pertama? Saya sedang dalam proses menambahkan objek BANYAK ke array, dan memutuskan untuk memasukkan masing-masing di awal, mendorong benda yang ada dengan satu. Membutuhkan array yang bisa berubah, dalam hal ini.
NSMutableArray *myMutableArray = [[NSMutableArray alloc] initWithCapacity:1];
[myMutableArray insertObject:aNewObject atIndex:0];
Atau cara 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 @[];
}
Ada cara mudah untuk melakukannya.
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"]
Saya harap ini membantu.
Saya tidak tahu adanya metode bawaan. Tapi, coding dengan tangan tidak terlalu sulit. Dengan asumsi elemen array yang Anda hadapi adalah objek NSNumber bertipe integer, dan 'arr' adalah NSMutableArray yang ingin Anda balikkan.
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];
}
Karena Anda mulai dengan NSArray maka Anda harus membuat array yang bisa berubah terlebih dahulu dengan konten NSArray asli ('origArray').
NSMutableArray * arr = [[NSMutableArray alloc] init];
[arr setArray:origArray];
Sunting: Memperbaiki n -> n / 2 dalam jumlah loop dan mengubah NSNumber ke id yang lebih umum karena saran dalam jawaban Brent.
Jika semua yang ingin Anda lakukan adalah beralih secara terbalik, coba ini:
// iterate backwards
nextIndex = (currentIndex == 0) ? [myArray count] - 1 : (currentIndex - 1) % [myArray count];
Anda dapat melakukan [myArrayCount] sekali dan menyimpannya ke variabel lokal (saya pikir itu mahal), tetapi saya juga menduga bahwa kompiler akan melakukan hal yang sama dengan kode seperti yang ditulis di atas.
Coba ini:
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];
}
Berikut ini adalah makro bagus yang akan berfungsi untuk NSMutableArray ATAU 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]];\
}\
}
Untuk menggunakan panggilan saja: reverseArray(myArray);