Geri çevirmem gerek NSArray
.
Örnek olarak:
[1,2,3,4,5]
olmalı: [5,4,3,2,1]
Bunu başarmanın en iyi yolu nedir?
Geri çevirmem gerek NSArray
.
Örnek olarak:
[1,2,3,4,5]
olmalı: [5,4,3,2,1]
Bunu başarmanın en iyi yolu nedir?
Yanıtlar:
Bir dizinin ters kopyasını elde etmek için, kullanarak danielpunkass'ın çözümüne bakın reverseObjectEnumerator
.
Değiştirilebilir bir diziyi tersine çevirmek için kodunuza aşağıdaki kategoriyi ekleyebilirsiniz:
@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
Eğer yararlanmak eğer çok daha kolay bir çözüm yoktur yerleşik reverseObjectEnumerator
üzerine yönteme NSArray
ve allObjects
yöntemin NSEnumerator
:
NSArray* reversedArray = [[startArray reverseObjectEnumerator] allObjects];
allObjects
henüz üzerinde hareket edilmemiş nesnelerle birlikte bir dizi döndürüleceği belgeleniyornextObject
:
Bu dizi, numaralandırıcının kalan tüm nesnelerini numaralandırılmış sırada içerir .
Bazı kriterler
1. reverseObjectEnumerator allObjects
Bu en hızlı yöntemdir:
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);
Sonuç: executionTime = 0.000026
2. Bir reverseObjectEnumerator üzerinden yineleme
Bu 1,5x ile 2,5x arasında daha yavaştır:
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);
Sonuç: executionTime = 0.000071
3. sortArrayUsingComparator
Bu 30x ile 40x arasında daha yavaştır (burada sürpriz yok):
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);
Sonuç: executionTime = 0.001100
Yani [[anArray reverseObjectEnumerator] allObjects]
bu hız ve kolaylığı geldiğinde eşi yoktur.
enumerateObjectsWithOptions:NSEnumerationReverse
?
enumerateObjectsWithOptions:NSEnumerationReverse
- ilk bir 0.000072
saniye içinde tamamlandı , blok yöntemi 0.000009
saniye içinde.
DasBoot'un doğru yaklaşımı var, ancak kodunda birkaç hata var. İşte herhangi bir NSMutableArray'i tersine çevirecek tamamen genel bir kod snippet'i:
/* 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];
}
Bunu bir C işlevinde sarabilir veya bonus puanlar için NSMutableArray'e eklemek için kategorileri kullanabilirsiniz. (Bu durumda, 'dizi' 'benlik' olur.) Ayrıca atayarak da onu optimize edebilirsiniz.[array count]
önce bir değişkene ve isterseniz bu değişkeni kullanarak .
Yalnızca normal bir NSArray'ınız varsa, onu tersine çevirmenin bir yolu yoktur, çünkü NSArray'ler değiştirilemez. Ancak ters çevrilmiş bir kopya oluşturabilirsiniz:
NSMutableArray * copy = [NSMutableArray arrayWithCapacity:[array count]];
for(int i = 0; i < [array count]; i++) {
[copy addObject:[array objectAtIndex:[array count] - i - 1]];
}
Veya tek bir satırda yapmak için bu küçük numarayı kullanın:
NSArray * copy = [[array reverseObjectEnumerator] allObjects];
Bir diziyi geriye doğru döngüye almak istiyorsanız, for
/ in
döngüsünü ile kullanabilirsiniz [array reverseObjectEnumerator]
, ancak kullanımı biraz daha etkilidir -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.)
}];
( Not : 2014 yılında beş yıllık Vakıf deneyimi, yeni bir Objective-C özelliği ve iki yorumdan birkaç ipucu ile önemli ölçüde güncellendi.)
Diğerlerinin yukarıdaki cevaplarını inceledikten ve Matt Gallagher'ın burada tartışmasını bulduktan sonra
Bunu öneriyorum:
NSMutableArray * reverseArray = [NSMutableArray arrayWithCapacity:[myArray count]];
for (id element in [myArray reverseObjectEnumerator]) {
[reverseArray addObject:element];
}
Matt'in gözlemlediği gibi:
Yukarıdaki durumda, - [NSArray reverseObjectEnumerator] öğesinin döngünün her yinelemesinde çalıştırılıp çalıştırılmayacağını merak edebilirsiniz - muhtemelen kodu yavaşlatır. <...>
Kısa bir süre sonra şöyle cevap verir:
<...> "toplama" ifadesi, for döngüsü başladığında yalnızca bir kez değerlendirilir. Bu, en iyi durumdur, çünkü "yineleme" ifadesine, döngünün yineleme başına performansını etkilemeden güvenli bir şekilde pahalı bir işlev koyabilirsiniz.
Georg Schölly'nin kategorileri çok güzel. Ancak, NSMutableArray için, dizin boş olduğunda dizinler için NSUIntegers kullanmak çökme ile sonuçlanır. Doğru kod:
@implementation NSMutableArray (Reverse)
- (void)reverse {
NSInteger i = 0;
NSInteger j = [self count] - 1;
while (i < j) {
[self exchangeObjectAtIndex:i
withObjectAtIndex:j];
i++;
j--;
}
}
@end
Kullanın enumerateObjectsWithOptions:NSEnumerationReverse usingBlock
. @ JohannesFahrenkrug'un yukarıdaki ölçütünü kullanarak, bu, aşağıdakilerden 8 kat daha hızlı tamamladı [[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];
}
Ters dizi ve içinden döngü:
[[[startArray reverseObjectEnumerator] allObjects] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
...
}];
Bana gelince, dizinin ilk başta nasıl doldurulduğunu düşündünüz mü? Bir diziye MANY nesneleri ekleme sürecindeydim ve her birini başlangıçta eklemeye karar verdim, mevcut nesneleri birer birer yukarı iterek. Bu durumda değiştirilebilir bir dizi gerekir.
NSMutableArray *myMutableArray = [[NSMutableArray alloc] initWithCapacity:1];
[myMutableArray insertObject:aNewObject atIndex:0];
Veya Scala-yolu:
-(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 @[];
}
Bunu yapmanın kolay bir yolu var.
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"]
Umarım bu yardımcı olur.
Yerleşik bir yöntem bilmiyorum. Ancak, elle kodlamak çok zor değildir. Karşılaştığınız dizinin öğelerinin, tamsayı türünde NSNumber nesneleri ve 'arr', tersine çevirmek istediğiniz NSMutableArray olduğunu varsayarsak.
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];
}
Bir NSArray ile başladığınız için, önce orijinal NSArray ('origArray') içeriğiyle mutable dizisini oluşturmanız gerekir.
NSMutableArray * arr = [[NSMutableArray alloc] init];
[arr setArray:origArray];
Düzenleme: Döngü sayısında n -> n / 2 düzeltildi ve Brent'in cevabındaki öneriler nedeniyle NSNumber'ı daha genel kimliğe değiştirdi.
Tek yapmak istediğiniz şey tersine yinelemekse, şunu deneyin:
// iterate backwards
nextIndex = (currentIndex == 0) ? [myArray count] - 1 : (currentIndex - 1) % [myArray count];
Bir kere [myArrayCount] yapabilir ve yerel bir değişkene kaydedebilirim (pahalı olduğunu düşünüyorum), ama aynı zamanda derleyicinin yukarıda yazılı kodla hemen hemen aynı şeyi yapacağını tahmin ediyorum.
Bunu dene:
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];
}
İşte NSMutableArray VEYA NSArray için çalışacak güzel bir makro :
#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]];\
}\
}
Kullanmak için arayın: reverseArray(myArray);