मैं NSArray पर कैसे पुनरावृति करूं?


जवाबों:


667

10.5 + / iOS के लिए आम तौर पर पसंदीदा कोड।

for (id object in array) {
    // do something with object
}

इस निर्माण का उपयोग किसी संग्रह में वस्तुओं की गणना करने के लिए किया जाता है जो NSFastEnumerationप्रोटोकॉल के अनुरूप होता है। इस दृष्टिकोण का एक गति लाभ है क्योंकि यह एक बफर में कई ऑब्जेक्ट्स (एक एकल विधि कॉल के माध्यम से प्राप्त) को इंगित करता है और पॉइंटर अंकगणित का उपयोग करके बफर के माध्यम से आगे बढ़ते हुए इसे पुनरावृत्त करता है। यह लूप के माध्यम से हर बार कॉल करने की तुलना में बहुत तेज है -objectAtIndex:

यह भी ध्यान देने योग्य है कि जब आप तकनीकी रूप से एक के माध्यम से कदम बढ़ाने के लिए फॉर-लूप का उपयोग कर सकते हैं NSEnumerator, तो मैंने पाया है कि यह तेजी से एन्यूमरेशन के गति लाभ के लगभग सभी को स्पष्ट करता है। इसका कारण यह है कि प्रत्येक कॉल पर बफर में केवल एक ऑब्जेक्ट NSEnumeratorके -countByEnumeratingWithState:objects:count:स्थानों का डिफ़ॉल्ट कार्यान्वयन ।

मैंने इसकी सूचना दी radar://6296108(NSEnumerators का तेज़ गणना सुस्त है) लेकिन इसे नॉट टू बी फिक्स्ड के रूप में लौटाया गया। कारण यह है कि तेजी से एन्यूमरेशन वस्तुओं के एक समूह को पूर्व-प्राप्त करता है, और यदि आप केवल एन्यूमरेटर में दिए गए बिंदु पर गणना करना चाहते हैं (जैसे कि जब तक कोई विशेष वस्तु नहीं मिलती है, या स्थिति पूरी हो जाती है) और बाहर तोड़ने पर उसी एन्यूमरेटर का उपयोग करें पाश की, यह अक्सर ऐसा होता है कि कई वस्तुओं को छोड़ दिया जाएगा।

यदि आप OS X 10.6 / iOS 4.0 और इसके बाद के संस्करण के लिए कोडिंग कर रहे हैं, तो आपके पास ब्लॉक-आधारित API का उपयोग करने के लिए सरणियों और अन्य संग्रहों को संकलित करने का विकल्प भी है:

[array enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
    // do something with object
}];

आप विकल्प तर्क के रूप में भी उपयोग कर सकते हैं -enumerateObjectsWithOptions:usingBlock:और पास NSEnumerationConcurrentऔर / या कर सकते हैं NSEnumerationReverse


10.4 या उससे पहले

पूर्व 10.5 के लिए मानक मुहावरे का उपयोग करना है NSEnumeratorऔर थोड़ी देर के लूप, जैसे:

NSEnumerator *e = [array objectEnumerator];
id object;
while (object = [e nextObject]) {
  // do something with object
}

मैं इसे सरल रखने की सलाह देता हूं। अपने आप को एक अरै टाइप प्रकार से बांधना अनम्य है, और उपयोग करने की शुद्ध गति में वृद्धि -objectAtIndex:10.5+ पर तेजी से एन्यूमरेशन के साथ वैसे भी सुधार के लिए महत्वहीन है। (तेज गणना वास्तव में अंतर्निहित डेटा संरचना पर सूचक अंकगणितीय का उपयोग करती है, और अधिकांश विधि कॉल को ओवरहेड निकाल देती है।) समय से पहले अनुकूलन एक अच्छा विचार नहीं है - इससे किसी भी समस्या का समाधान करने के लिए गड़बड़ कोड होता है जो आपकी अड़चन नहीं है।

उपयोग करते समय -objectEnumerator, आप बहुत आसानी से एक और संग्रहणीय संग्रह में बदल जाते हैं (जैसे कि NSSet, ए NSDictionary, की आदि), या यहां तक ​​कि -reverseObjectEnumeratorकिसी अन्य कोड परिवर्तन के साथ किसी सरणी को पीछे की ओर ले जाने के लिए स्विच करें । यदि पुनरावृति कोड एक विधि में है, तो आप किसी में भी पास कर सकते हैं NSEnumeratorऔर कोड को इस बात की परवाह करने की आवश्यकता नहीं है कि वह क्या कर रहा है। इसके अलावा, NSEnumerator(कम से कम जो Apple कोड द्वारा प्रदान किया गया है) संग्रह को बरकरार रखता है क्योंकि यह अधिक ऑब्जेक्ट हैं, इसलिए आपको यह चिंता करने की ज़रूरत नहीं है कि ऑटोरेल्ड ऑब्जेक्ट कितनी देर तक मौजूद रहेगा।

शायद सबसे बड़ी चीज़ NSEnumerator(या तेज़ गणना) आपकी रक्षा करती है, जब आप इसे एन्यूमरेट कर रहे होते हैं तो आपके ज्ञान के बिना आपके पास एक परिवर्तनशील संग्रह (सरणी या अन्यथा) परिवर्तन होता है। यदि आप अनुक्रमणिका द्वारा वस्तुओं तक पहुंचते हैं, तो आप अजीब अपवादों या ऑफ-बाय-वन त्रुटियों (अक्सर समस्या होने के बाद लंबे समय तक) में चल सकते हैं जो डीबग करने के लिए भीषण हो सकते हैं। मानक मुहावरों में से एक का उपयोग करने वाले अभिगम का एक "विफल-तेज़" व्यवहार होता है, इसलिए समस्या (गलत कोड के कारण) तुरंत प्रकट होगी जब आप उत्परिवर्तन होने के बाद अगली वस्तु तक पहुंचने का प्रयास करेंगे। जैसे-जैसे प्रोग्राम अधिक जटिल और बहु-थ्रेडेड होते जाते हैं, या यहां तक ​​कि कुछ पर निर्भर करते हैं, जो तृतीय-पक्ष कोड को संशोधित कर सकता है, नाजुक गणना कोड तेजी से समस्याग्रस्त हो जाता है। इनकैप्सुलेशन और एब्स्ट्रक्शन FTW! :-)



28
नोट: अधिकांश संकलक "जबकि (वस्तु = [अगला अगला])" के बारे में चेतावनी देंगे। इस मामले में, आप वास्तव में == के बजाय = का उपयोग करने का मतलब है। चेतावनियों को दबाने के लिए, आप अतिरिक्त कोष्ठक जोड़ सकते हैं: "जबकि ((वस्तु = [e अगला अगला]))"।
एडम रोसेनफील्ड

NSEnumerator के साथ याद रखने वाली एक और बात यह है कि यह objectWithIndex दृष्टिकोण की तुलना में अधिक मेमोरी (सरणी की प्रतिलिपि बनाता है) का उपयोग करेगा।
मरेरिख

@QuinnTaylor का उपयोग करना for (id object in array), सरणी में वस्तुओं को वर्तमान सूचकांक का निर्धारण करने का एक तरीका है, या एक अलग काउंटर को शामिल करने की आवश्यकता है?
कोडरमा

1
यदि आपको यह उपलब्ध है तो आपको एक अलग काउंटर की आवश्यकता होगी, लेकिन मैं ब्लॉक-आधारित गणना (जिसमें सूचकांक शामिल करता है) पर विचार करना चाहूंगा।
क्विन टेलर

मैं अजीब हूँ, लेकिन मैं forइस तरह एक लूप का उपयोग करता हूं :for(;;) { id object = [ e nextObject ] ; if ( !e ) { break ; } ... your loop operation ... }
नील्सबॉट

125

OS X 10.4.x और पिछले के लिए:

 int i;
 for (i = 0; i < [myArray count]; i++) {
   id myArrayElement = [myArray objectAtIndex:i];
   ...do something useful with myArrayElement
 }

OS X 10.5.x (या iPhone) और उससे आगे के लिए:

for (id myArrayElement in myArray) {
   ...do something useful with myArrayElement
}

2
पहले उदाहरण में, आपको लूप के बाहर इंट की घोषणा करने की भी आवश्यकता नहीं है। यह ठीक वैसे ही काम करता है, और वैरिएबल को अच्छी तरह से स्कोप करता है ताकि आप इसे बाद में फिर से उपयोग कर सकें, यदि आवश्यक हो तो: (int i = 0; मैं <[myArray count]; i ++) ... लेकिन यह भी जान लें कि कॉलिंग -काउंट हर बार; सरणी के माध्यम से -objectAtIndex का उपयोग कर के लाभ को रद्द कर सकते हैं:
क्विन टेलर

1
और वास्तव में, यदि आप एक उत्परिवर्तित संग्रह की गणना कर रहे हैं, तो लूप के माध्यम से हर बार गिनती की जांच करना तकनीकी रूप से अधिक सही है। मैंने अपने उत्तर को स्पष्ट करने के लिए स्पष्ट किया कि NSEnumerator या NSFastEnumeration का उपयोग करके सरणी के समवर्ती म्यूटेशन से रक्षा कर सकते हैं।
क्विन टेलर

के लिए (int i = 0; ...) contruct एक सी भाषा बोली है (C99 विश्वास है), जो मैं खुद उपयोग करता हूं, लेकिन मुझे यकीन नहीं था कि यह XCode डिफ़ॉल्ट था।
मृत्युंजय

C99 Xcode 3.1.x के माध्यम से डिफ़ॉल्ट है - कुछ भविष्य के बिंदु पर डिफ़ॉल्ट GNU99 में बदल जाएगा, जो (अन्य बातों के अलावा) अनाम यूनियनों और संरचनाओं का समर्थन करता है। यह अच्छा होना चाहिए ...
क्विन टेलर

2
उपयोग करना for (NSUInteger i = 0, count = [myArray count]; i < count; i++)संभवतः सबसे कुशल और संक्षिप्त है जिसे आप इस दृष्टिकोण के लिए प्राप्त करेंगे।
क्विन टेलर

17

परीक्षण और स्रोत कोड के परिणाम नीचे हैं (आप ऐप में पुनरावृत्तियों की संख्या निर्धारित कर सकते हैं)। समय मिलीसेकंड में है, और प्रत्येक प्रविष्टि 5-10 बार परीक्षण चलाने का औसत परिणाम है। मैंने पाया कि आमतौर पर यह 2-3 महत्वपूर्ण अंकों के लिए सटीक होता है और इसके बाद यह प्रत्येक रन के साथ बदलता रहता है। यह 1% से कम की त्रुटि का मार्जिन देता है। यह परीक्षण एक iPhone 3G पर चल रहा था क्योंकि मैं जिस लक्ष्य प्लेटफ़ॉर्म में रुचि रखता था।

numberOfItems   NSArray (ms)    C Array (ms)    Ratio
100             0.39            0.0025          156
191             0.61            0.0028          218
3,256           12.5            0.026           481
4,789           16              0.037           432
6,794           21              0.050           420
10,919          36              0.081           444
19,731          64              0.15            427
22,030          75              0.162           463
32,758          109             0.24            454
77,969          258             0.57            453
100,000         390             0.73            534

कोको को डेटा सेट्स (एनएसएडर, एनएसएआरईआर, एनएसएसईटी आदि) से निपटने के लिए प्रदान की जाने वाली कक्षाएं, सूचना प्रबंधन के लिए एक बहुत अच्छा इंटरफ़ेस प्रदान करती हैं, बिना स्मृति प्रबंधन, वास्तविककरण आदि की नौकरशाही के बारे में चिंता किए बिना बेशक यह एक लागत पर आता है। । मुझे लगता है कि यह स्पष्ट है कि NSNumbers के NSArray का उपयोग करना सरल पुनरावृत्तियों के लिए C Array की तुलना में धीमा होने वाला है, इसलिए मैंने कुछ परीक्षण करने का निर्णय लिया, और परिणाम बहुत चौंकाने वाले थे! मैं यह बुरा होने की उम्मीद नहीं कर रहा था। नोट: ये परीक्षण एक iPhone 3G पर आयोजित किए जाते हैं, क्योंकि मैं जिस लक्ष्य प्लेटफ़ॉर्म में रुचि रखता था।

इस परीक्षण में मैं एक सी फ्लोट * और NSNumbers के NSArray के बीच बहुत ही सरल यादृच्छिक अभिगम प्रदर्शन तुलना करता हूं

मैं प्रत्येक सरणी की सामग्री को समेटने के लिए एक सरल लूप बनाता हूं और उन्हें mach_absolute_time () का उपयोग करके समय देता हूं। NSMutableArray औसतन 400 बार अधिक समय लेता है !! (400 प्रतिशत नहीं, सिर्फ 400 गुना लंबा! यानी 40,000% लंबा!)।

हैडर:

// Array_Speed_TestViewController.h

// ऐरे स्पीड टेस्ट

// 05/02/2009 को मेहमत एकेन द्वारा बनाया गया।

// कॉपीराइट MSA विजुअल्स लिमिटेड 2009. सभी अधिकार सुरक्षित।

#import <UIKit/UIKit.h>

@interface Array_Speed_TestViewController : UIViewController {

    int                     numberOfItems;          // number of items in array

    float                   *cArray;                // normal c array

    NSMutableArray          *nsArray;               // ns array

    double                  machTimerMillisMult;    // multiplier to convert mach_absolute_time() to milliseconds



    IBOutlet    UISlider    *sliderCount;

    IBOutlet    UILabel     *labelCount;


    IBOutlet    UILabel     *labelResults;

}


-(IBAction) doNSArray:(id)sender;

-(IBAction) doCArray:(id)sender;

-(IBAction) sliderChanged:(id)sender;


@end

कार्यान्वयन:

// Array_Speed_TestViewController.m

// ऐरे स्पीड टेस्ट

// 05/02/2009 को मेहमत एकेन द्वारा बनाया गया।

// कॉपीराइट MSA विजुअल्स लिमिटेड 2009. सभी अधिकार सुरक्षित।

    #import "Array_Speed_TestViewController.h"
    #include <mach/mach.h>
    #include <mach/mach_time.h>

 @implementation Array_Speed_TestViewController



 // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.

- (void)viewDidLoad {

    NSLog(@"viewDidLoad");


    [super viewDidLoad];


    cArray      = NULL;

    nsArray     = NULL;


    // read initial slider value setup accordingly

    [self sliderChanged:sliderCount];


    // get mach timer unit size and calculater millisecond factor

    mach_timebase_info_data_t info;

    mach_timebase_info(&info);

    machTimerMillisMult = (double)info.numer / ((double)info.denom * 1000000.0);

    NSLog(@"machTimerMillisMult = %f", machTimerMillisMult);

}



// pass in results of mach_absolute_time()

// this converts to milliseconds and outputs to the label

-(void)displayResult:(uint64_t)duration {

    double millis = duration * machTimerMillisMult;


    NSLog(@"displayResult: %f milliseconds", millis);


    NSString *str = [[NSString alloc] initWithFormat:@"%f milliseconds", millis];

    [labelResults setText:str];

    [str release];

}




// process using NSArray

-(IBAction) doNSArray:(id)sender {

    NSLog(@"doNSArray: %@", sender);


    uint64_t startTime = mach_absolute_time();

    float total = 0;

    for(int i=0; i<numberOfItems; i++) {

        total += [[nsArray objectAtIndex:i] floatValue];

    }

    [self displayResult:mach_absolute_time() - startTime];

}




// process using C Array

-(IBAction) doCArray:(id)sender {

    NSLog(@"doCArray: %@", sender);


    uint64_t start = mach_absolute_time();

    float total = 0;

    for(int i=0; i<numberOfItems; i++) {

        total += cArray[i];

    }

    [self displayResult:mach_absolute_time() - start];

}



// allocate NSArray and C Array 

-(void) allocateArrays {

    NSLog(@"allocateArrays");


    // allocate c array

    if(cArray) delete cArray;

    cArray = new float[numberOfItems];


    // allocate NSArray

    [nsArray release];

    nsArray = [[NSMutableArray alloc] initWithCapacity:numberOfItems];



    // fill with random values

    for(int i=0; i<numberOfItems; i++) {

        // add number to c array

        cArray[i] = random() * 1.0f/(RAND_MAX+1);


        // add number to NSArray

        NSNumber *number = [[NSNumber alloc] initWithFloat:cArray[i]];

        [nsArray addObject:number];

        [number release];

    }


}



// callback for when slider is changed

-(IBAction) sliderChanged:(id)sender {

    numberOfItems = sliderCount.value;

    NSLog(@"sliderChanged: %@, %i", sender, numberOfItems);


    NSString *str = [[NSString alloc] initWithFormat:@"%i items", numberOfItems];

    [labelCount setText:str];

    [str release];


    [self allocateArrays];

}



//cleanup

- (void)dealloc {

    [nsArray release];

    if(cArray) delete cArray;


    [super dealloc];

}


@end

प्रेषक: ज्ञापन

////////////////////

ब्लॉक की शुरुआत के बाद से उपलब्ध है, यह ब्लॉक के साथ एक सरणी को पुनरावृत्त करने की अनुमति देता है। इसका सिंटैक्स तेज़ एन्यूमरेशन जितना अच्छा नहीं है, लेकिन एक बहुत ही दिलचस्प विशेषता है: समवर्ती गणना। यदि गणना क्रम महत्वपूर्ण नहीं है और नौकरियों को लॉक किए बिना समानांतर में किया जा सकता है, तो यह मल्टी-कोर सिस्टम पर काफी गति प्रदान कर सकता है। समवर्ती गणन अनुभाग में इसके बारे में अधिक।

[myArray enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {
    [self doSomethingWith:object];
}];
[myArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    [self doSomethingWith:object];
}];

/////////// NSFastEnumerator

तेज गणना के पीछे का विचार पुनरावृत्ति को अनुकूलित करने के लिए तेज सी सरणी पहुंच का उपयोग करना है। यह न केवल पारंपरिक NSEnumerator की तुलना में तेज़ माना जाता है, बल्कि ऑब्जेक्टिव-सी 2.0 भी बहुत संक्षिप्त वाक्य-विन्यास प्रदान करता है।

id object;
for (object in myArray) {
    [self doSomethingWith:object];
}

/////////////////

NSEnumerator

यह बाहरी पुनरावृत्ति का एक रूप है: [myArray objectEnumerator] एक वस्तु लौटाता है। इस ऑब्जेक्ट में अगली विधि है, जिसे हम लूप में कॉल कर सकते हैं जब तक कि यह शून्य नहीं लौटाता

NSEnumerator *enumerator = [myArray objectEnumerator];
id object;
while (object = [enumerator nextObject]) {
    [self doSomethingWith:object];
}

/////////////////

objectAtIndex: गणना

एक लूप का उपयोग करना जो एक पूर्णांक को बढ़ाता है और ऑब्जेक्ट का उपयोग करते हुए [myArray objectAtIndex: index] का उपयोग करता है, एन्यूमरेशन का सबसे मूल रूप है।

NSUInteger count = [myArray count];
for (NSUInteger index = 0; index < count ; index++) {
    [self doSomethingWith:[myArray objectAtIndex:index]];
}

////////////// से: darkdust.net


12

तीन तरीके हैं:

        //NSArray
    NSArray *arrData = @[@1,@2,@3,@4];

    // 1.Classical
    for (int i=0; i< [arrData count]; i++){
        NSLog(@"[%d]:%@",i,arrData[i]);
    }

    // 2.Fast iteration
    for (id element in arrData){
        NSLog(@"%@",element);
    }

    // 3.Blocks
    [arrData enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
         NSLog(@"[%lu]:%@",idx,obj);
         // Set stop to YES in case you want to break the iteration
    }];
  1. निष्पादन में सबसे तेज़ तरीका है, और 3. स्वत: पूर्णता के साथ पुनरावृति लिफाफा लिखना भूल जाते हैं।

7

eachअपने में विधि जोड़ें NSArray category, आपको इसकी बहुत आवश्यकता है

ObjectiveSugar से लिया गया कोड

- (void)each:(void (^)(id object))block {
    [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        block(obj);
    }];
}

5

यहां बताया गया है कि आप स्ट्रिंग की एक सरणी कैसे घोषित करते हैं और उन पर पुनरावृति करते हैं:

NSArray *langs = @[@"es", @"en", @"pt", @"it", @"fr"];

for (int i = 0; i < [langs count]; i++) {
  NSString *lang = (NSString*) [langs objectAtIndex:i];
  NSLog(@"%@, ",lang);
}

0

स्विफ्ट के लिए

let arrayNumbers = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

// 1
for (index, value) in arrayNumbers.enumerated() {
    print(index, value)
    //... do somthing with array value and index
}


//2
for value in arrayNumbers {
    print(value)
    //... do somthing with array value
}

-1

यह करो :-

for (id object in array) 
{
        // statement
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.