سؤال

أحتاج إلى عكس بلدي NSArray.

كمثال:

[1,2,3,4,5] يجب أن تصبح: [5,4,3,2,1]

ما هي أفضل طريقة لتحقيق ذلك؟

هل كانت مفيدة؟

المحلول

للحصول على نسخة عكسية من صفيف، انظر حل danielpunkass استخدام reverseObjectEnumerator.

لعكس مجموعة قابلة للتغيير، يمكنك إضافة الفئة التالية إلى التعليمات البرمجية الخاصة بك:

@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

نصائح أخرى

هناك حلا أسهل بكثير، إذا كنت تستفيد من المدمج reverseObjectEnumerator طريقة بشأن NSArray, ، و ال allObjects طريقة NSEnumerator:

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

allObjects موثقة كما إرجاع مجموعة مع الكائنات التي لم يتم اجتيازها بعد nextObject, ، مرتب:

يحتوي هذا الصفيف على جميع الكائنات المتبقية من العداد في أمر تعداد.

بعض المعايير

1. عثرت allobjects.

هذه هي أسرع طريقة:

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

نتيجة: executionTime = 0.000026

2. تكرار فوق عربسة

هذا بين 1.5x و 2.5x أبطأ:

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

نتيجة: executionTime = 0.000071

3. SortedRayusingComparator.

هذا بين 30x و 40x أبطأ (لا مفاجآت هنا):

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

نتيجة: executionTime = 0.001100

وبالتالي [[anArray reverseObjectEnumerator] allObjects] هو الفائز الواضح عندما يتعلق الأمر بالسرعة والسهولة.

Dasboot لديه النهج الصحيح، ولكن هناك بعض الأخطاء في كوده. إليك مقتطف رمز عام تماما سيعكس أي nsmutablerray في مكانه:

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

يمكنك التفاف أنه في وظيفة C، أو للحصول على نقاط المكافأة، استخدم الفئات لإضافتها إلى nsmutablerray. (في هذه الحالة، "صفيف" ستصبح "الذات"). يمكنك أيضا تحسينه عن طريق تعيين [array count] إلى متغير قبل الحلقة واستخدام هذا المتغير، إذا كنت ترغب في ذلك.

إذا كان لديك سوى NSArray العادية، فلا توجد طريقة لعكسها في مكانها، لأن NSARRAYS لا يمكن تعديلها. ولكن يمكنك إجراء نسخة عكسية:

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

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

أو استخدم هذه الخدعة الصغيرة للقيام بذلك في سطر واحد:

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

إذا كنت ترغب فقط في حلقة على صفيف للخلف، يمكنك استخدام 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.)
}];

(ملحوظة: تحديث كبير في عام 2014 مع خمس سنوات أخرى من الخبرة المؤسسة، ميزة هدف جديد أو اثنين، ونصائح زوجين من التعليقات.)

بعد مراجعة إجابات الآخر أعلاه والعثور عليها مناقشة مات غالاغر هنا

أقترح هذا:

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

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

كما يلاحظ مات:

في الحالة المذكورة أعلاه، قد تتساءل عما إذا كنت - سيتم تشغيل [NSARRAY TOXOBITENUMERATORATOR) على كل تكرار للحلقة - يحتمل أن يتباطأ التعليمات البرمجية. <...>

بعد ذلك بوقت قصير، يجيب هكذا:

<...> يتم تقييم تعبير "مجموعة" مرة واحدة فقط، عندما يبدأ حلقة. هذه هي أفضل حالة، نظرا لأنك تتمكن من وضع وظيفة باهظة الثمن في تعبير "مجموعة" دون التأثير على أداء التوافق في الحلقة.

فئات جورج شوللي لطيفة جدا. ومع ذلك، بالنسبة إلى NSMutablerray، فإن استخدام NSUINTTGERS للمؤشرات ينتج عنه تعطل عندما يكون الصفيف فارغا. الكود الصحيح هو:

@implementation NSMutableArray (Reverse)

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

        i++;
        j--;
    }
}

@end

الطريقة الأكثر فعالية لتعداد صفيف في الاتجاه المعاكس:

يستخدم enumerateObjectsWithOptions:NSEnumerationReverse usingBlock. وبعد باستخدام معيار JohannesfahrenkRug أعلاه، اكتمال هذا 8x أسرع من [[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];
}

مجموعة عكسية وحلقات من خلالها:

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

لتحديث هذا، في SWIFT يمكن القيام به بسهولة مع:

array.reverse()

بالنسبة لي، هل فكرت في كيفية ملء الصفيف في المقام الأول؟ كنت في عملية إضافة العديد من الكائنات إلى صفيف، وقررت إدراج كل واحد في البداية، مما دفع أي كائنات موجودة لأحد. يتطلب مجموعة قابلة للتغيير، في هذه الحالة.

NSMutableArray *myMutableArray = [[NSMutableArray alloc] initWithCapacity:1];
[myMutableArray insertObject:aNewObject atIndex:0];

أو طريقة 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 @[];
}

أنا لا أعرف أي طريقة مبنية. ولكن، الترميز باليد ليست صعبة للغاية. على افتراض أن عناصر الصفيف التي تتعامل معها هي كائنات NSNumber من نوع عدد صحيح، و "ARR" هي nsmutablerray التي تريد عكسها.

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

نظرا لأنك تبدأ ب NSAray، فعليك إنشاء صفيف قابل للتغيير أولا مع محتويات NSArray الأصلية ("Original" ("Origharay").

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

تحرير: ثابت N -> N / 2 في عدد الحلقة وتغيير NSNumber إلى معرف أكثر عام بسبب الاقتراحات في إجابة برنت.

إذا كان كل ما تريد القيام به هو تكرر في الاتجاه المعاكس، فجرب هذا:

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

يمكنك القيام به [myarraycount] مرة واحدة وحفظها بمتغير محلي (أعتقد أنه باهظ الثمن)، لكنني أظن أيضا أن المحول البرمجي سيفعل نفس الشيء مع الكود كما هو مكتوب أعلاه.

Swift 3 Syntax:

let reversedArray = array.reversed()

جرب هذا:

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

هناك طريقة سهلة للقيام بذلك.

    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"]

آمل أن يساعد هذا.

إليك ماكرو لطيف سيعمل لأي من nsmutablerray أو 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]];\
    }\
}

لاستخدام مكالمة فقط: reverseArray(myArray);

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top