আমি কীভাবে এনএসএরে পুনরুক্তি করব?


449

আমি একটি এনএসআরির মাধ্যমে পুনরাবৃত্তি করার জন্য স্ট্যান্ডার্ড আইডিয়ামটি সন্ধান করছি। আমার কোডটি ওএস এক্স 10.4+ এর জন্য উপযুক্ত হতে হবে।

উত্তর:


667

10.5 + / iOS এর জন্য সাধারণত পছন্দের কোড।

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

এই কনস্ট্রাক্টটি কোনও সংকলনে অবজেক্টগুলি গণনার জন্য ব্যবহৃত হয় যা NSFastEnumerationপ্রোটোকলের সাথে সামঞ্জস্য করে। এই পদ্ধতির একটি গতি সুবিধা রয়েছে কারণ এটি একটি বাফারে বিভিন্ন বস্তুর (একক পদ্ধতি কলের মাধ্যমে প্রাপ্ত) পয়েন্টার সংরক্ষণ করে এবং পয়েন্টার পাটিগণিত ব্যবহার করে বাফারের মাধ্যমে অগ্রসর হয়ে তাদের মাধ্যমে পুনরাবৃত্তি করে। লুপের মাধ্যমে প্রতিবার কল করার চেয়ে এটি অনেক দ্রুত -objectAtIndex:

এটি লক্ষণীয়ও যে আপনি যখন প্রযুক্তিগতভাবে কোনওটির মধ্য দিয়ে যাওয়ার জন্য একটি ইন-লুপটি ব্যবহার করতে পারেন NSEnumerator, আমি খুঁজে পেয়েছি যে এটি দ্রুত গণনার গতি সুবিধার জন্য কার্যত সমস্তটি বাতিল করে দেয়। কারণটি হ'ল প্রতিটি কলের ডিফল্ট NSEnumeratorরূপায়ণ -countByEnumeratingWithState:objects:count:বাফারে একটি মাত্র অবজেক্ট রাখে।

আমি radar://6296108এটিতে জানিয়েছি (এনএসইউমেনেটরগুলির দ্রুত গণনাটি স্বাচ্ছন্দ্যযুক্ত) তবে এটি নট টু ফিক্স হিসাবে ফিরিয়ে দেওয়া হয়েছিল। কারণটি হ'ল দ্রুত গণনা একটি বস্তুর একটি দলকে পূর্বে নিয়ে আসে এবং আপনি যদি কেবলমাত্র গণকের একটি নির্দিষ্ট বিন্দুতে গণনা করতে চান (যেমন কোনও নির্দিষ্ট অবজেক্টটি পাওয়া না যাওয়া বা শর্ত পূরণ না হওয়া পর্যন্ত) এবং বিচ্ছিন্ন হওয়ার পরে একই গণকটি ব্যবহার করতে চান লুপটির মধ্যে প্রায়শই এমন হয় যে বেশ কয়েকটি বস্তু এড়িয়ে যায় sk

আপনি যদি ওএস এক্স 10.6 / আইওএস 4.0 এবং এর চেয়ে বেশি কোডিং করে থাকেন তবে আপনার কাছে অ্যারে এবং অন্যান্য সংগ্রহগুলি গণনা করতে ব্লক-ভিত্তিক এপিআইগুলি ব্যবহার করার বিকল্প রয়েছে:

[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(কমপক্ষে অ্যাপল কোড দ্বারা সরবরাহিত) যতক্ষণ বেশি অবজেক্ট থাকে ততক্ষণ এটি গণনা করে তা সংগ্রহ করে রাখে, সুতরাং স্বতঃস্ফূর্ত অবজেক্টটি আর কত দিন থাকবে তা নিয়ে আপনাকে চিন্তিত হওয়ার দরকার নেই।

সম্ভবত NSEnumerator(বা দ্রুত গণনা) সবচেয়ে বড় জিনিসটি আপনাকে সুরক্ষা দেওয়ার সময় আপনার অজানা ছাড়াই কোনও পরিবর্তনীয় সংগ্রহ (অ্যারে বা অন্যথায়) পরিবর্তন করা থেকে রক্ষা করে। আপনি যদি সূচকে অবজেক্টগুলিতে অ্যাক্সেস করেন তবে আপনি অদ্ভুত ব্যতিক্রম বা একের পর এক ত্রুটিগুলিতে দৌড়াতে পারেন (প্রায়শই সমস্যাটি আসার অনেক পরে) যা ডিবাগ করার জন্য ভয়াবহ হতে পারে। স্ট্যান্ডার্ড আইডিয়ামগুলির মধ্যে একটি ব্যবহার করে গণনার "ব্যর্থ-দ্রুত" আচরণ রয়েছে, সুতরাং সমস্যাটি (ভুল কোড দ্বারা সৃষ্ট) তত্ক্ষণাত প্রকাশ পাবে যখন আপনি রূপান্তর হওয়ার পরে পরবর্তী বস্তুটি অ্যাক্সেস করার চেষ্টা করবেন। প্রোগ্রামগুলি আরও জটিল এবং বহু-থ্রেডযুক্ত হয়ে উঠলে বা তৃতীয়-পক্ষের কোডটি সংশোধন করতে পারে এমন কোনও কিছুর উপর নির্ভর করে, ভঙ্গুর অঙ্কের কোডটি ক্রমবর্ধমান সমস্যাযুক্ত হয়ে ওঠে। এনক্যাপসুলেশন এবং বিমূর্ততা FTW! :-)



28
দ্রষ্টব্য: বেশিরভাগ সংকলকগণ "যখন (অবজেক্ট = [ই নেক্সটবজেক্ট])" সম্পর্কে একটি সতর্কতা দেবেন। এই ক্ষেত্রে, আপনি আসলে == এর পরিবর্তে = ব্যবহার করতে চাইছেন। সতর্কতাগুলি দমন করতে, আপনি অতিরিক্ত বন্ধনী যুক্ত করতে পারেন: "যখন ((অবজেক্ট = [ই নেক্সট অবজেক্ট]))" "
অ্যাডাম রোজেনফিল্ড

এনএসইউনিমরেটারের সাথে আরেকটি জিনিস মনে রাখার বিষয় হ'ল এটি অবজেক্ট উইথ ইন্ডেক্স পদ্ধতির চেয়ে বেশি মেমরি (অ্যারের অনুলিপি তৈরি করবে) ব্যবহার করবে।
গিয়েছে

@ কুইনটায়লর ইউজিং for (id object in array), অ্যারেতে অবজেক্টস কারেন্ট ইনডেক্স নির্ধারণের জন্য একটি উপায় বা অন্য একটি পৃথক কাউন্টারকে অন্তর্ভুক্ত করা দরকার কি?
কোড্রামামা

1
আপনার একটি পৃথক কাউন্টার দরকার, তবে আমি ব্লক-ভিত্তিক গণনা বিবেচনা করার পরামর্শ দিচ্ছি (যা সূচকটি অন্তর্ভুক্ত করে) যদি এটি আপনার কাছে উপলব্ধ থাকে।
কুইন টেলর

আমি অদ্ভুত, তবে আমি forfor(;;) { id object = [ e nextObject ] ; if ( !e ) { break ; } ... your loop operation ... }
এটির

125

ওএস এক্স 10.4.x এবং এর আগেরটির জন্য:

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

ওএস এক্স 10.5.x (বা আইফোন) এবং এর বাইরেও:

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

2
প্রথম উদাহরণে, আপনাকে এমনকি লুপের বাইরে ইন্ট ঘোষণা করতে হবে না। এটি ঠিক একইভাবে কাজ করে এবং ভেরিয়েবলটি খুব ভালভাবে সরিয়ে দেয় যাতে প্রয়োজন হলে আপনি পরে এটি পুনরায় ব্যবহার করতে পারেন: (int i = 0; i <[আমারআরে গণনা]; i++) ... তবে, সচেতন থাকুন যে প্রতিবার কলিং-অ্যাকাউন্ট অ্যারের মাধ্যমে -বজেক্টএটিএন্ডেক্স ব্যবহারের সুবিধাটি বাতিল করতে পারে:
কুইন টেলর

1
এবং বাস্তবে, আপনি যদি একটি পরিবর্তনীয় সংগ্রহের সংখ্যা গণনা করছেন তবে প্রতিবার লুপের মাধ্যমে গণনাটি পরীক্ষা করা প্রযুক্তিগতভাবে আরও সঠিক। আমি আমার উত্তরটি স্পষ্ট করে বলেছিলাম যে এনএসইউনিমেটর বা এনএসএফস্টএইউমেন্টেশন ব্যবহার করে অ্যারের একযোগে পরিবর্তন থেকে রক্ষা পেতে পারে।
কুইন টেলর

(Int i = 0; ...) এর জন্য চুক্তিটি হ'ল সি ভাষার উপভাষা (সি 99 বিশ্বাস করা হয়), যা আমি নিজে ব্যবহার করি তবে আমি নিশ্চিত নই যে এটি এক্সকোড ডিফল্ট।
মৃতেরখ

সি 99 এক্সকোড 3.1.x এর মাধ্যমে ডিফল্ট আপ - ভবিষ্যতের কোনও সময়ে ডিফল্টটি GNU99 এ পরিবর্তিত হবে, যা (অন্যান্য বিষয়ের মধ্যে) বেনামী ইউনিয়ন এবং স্ট্রাক্টকে সমর্থন করে। এটি চমৎকার হওয়া উচিত ...
কুইন টেলর

2
ব্যবহার for (NSUInteger i = 0, count = [myArray count]; i < count; i++)সম্ভবত আপনি এই পদ্ধতির জন্য পাবেন সবচেয়ে দক্ষ এবং সংক্ষিপ্ত।
কুইন টেলর

17

পরীক্ষার ফলাফল এবং উত্স কোড নীচে রয়েছে (আপনি অ্যাপে পুনরাবৃত্তির সংখ্যা সেট করতে পারেন)। সময়টি মিলি সেকেন্ডে রয়েছে এবং প্রতিটি এন্ট্রি 5-10 বার পরীক্ষা চালানোর গড় ফলাফল। আমি দেখেছি যে এটি সাধারণত ২-৩ টি উল্লেখযোগ্য অঙ্কের সাথে সঠিক এবং এর পরে এটি প্রতিটি রানের সাথে পৃথক হবে। এটি 1% এরও কম ত্রুটির একটি মার্জিন দেয়। আমি আগ্রহী টার্গেট প্ল্যাটফর্মটি হিসাবে আইফোন 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

ডেটা সেটগুলি পরিচালনা করার জন্য কোকো দ্বারা সরবরাহিত ক্লাসগুলি (এনএসডি অভিধান, এনএসআরে, এনএসএসেট ইত্যাদি) মেমরি পরিচালনা, পুনর্নির্মাণ ইত্যাদি সম্পর্কিত আমলাতন্ত্র সম্পর্কে চিন্তা না করেই তথ্য পরিচালনার জন্য খুব সুন্দর ইন্টারফেস সরবরাহ করে তবে অবশ্যই এটি ব্যয় করে আসে যদিও । আমি মনে করি এটি একেবারেই সুস্পষ্ট যে বলে যে এনএসএন নাম্বারগুলির একটি এনএসআরাই ব্যবহার করা সহজ পুনরাবৃত্তির জন্য একটি সি অ্যারের ফ্লোটের চেয়ে ধীর হতে চলেছে, তাই আমি কিছু পরীক্ষা করার সিদ্ধান্ত নিয়েছি, এবং ফলাফলগুলি বেশ চমকপ্রদ ছিল! আমি এটি খারাপ হওয়ার আশা করছিলাম না। দ্রষ্টব্য: এই পরীক্ষাগুলি একটি আইফোন 3G তে পরিচালিত হয় কারণ এটি আমি আগ্রহী টার্গেট প্ল্যাটফর্ম।

এই পরীক্ষায় আমি সি সি ফ্লোট * এবং এনএসএন নাম্বার এনএসআরয়ের মধ্যে খুব সাধারণ র্যান্ডম অ্যাক্সেস পারফরম্যান্স তুলনা করি

আমি প্রতিটি অ্যারের সামগ্রীর যোগফল এবং ম্যাক_অবসুলিউট_টাইম () ব্যবহার করে সময় দেওয়ার জন্য একটি সাধারণ লুপ তৈরি করি। NSMutableArray গড়ে 400 গুণ বেশি সময় নেয়! (৪০০ শতাংশ নয়, মাত্র ৪০০ গুণ বেশি লম্বা! এটি ৪০,০০০% দীর্ঘ!)।

শিরোলেখ:

// অ্যারে_স্পিড_টেষ্ট ভিউকন্ট্রোল.আর

// অ্যারে গতির পরীক্ষা

// 05/02/2009 তারিখে মেহমেট আক্টেন তৈরি করেছেন।

// কপিরাইট এমএসএ ভিজ্যুয়ালস লিমিটেড 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

বাস্তবায়ন:

// অ্যারে_স্পিড_টেষ্ট ভিউকন্ট্রোলআরএম

// অ্যারে গতির পরীক্ষা

// 05/02/2009 তারিখে মেহমেট আক্টেন তৈরি করেছেন।

// কপিরাইট এমএসএ ভিজ্যুয়ালস লিমিটেড 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

থেকে: memo.tv

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

ব্লকগুলির প্রবর্তনের পর থেকে উপলব্ধ, এটি ব্লক সহ একটি অ্যারে পুনরুক্ত করতে দেয়। এর বাক্য গঠনটি দ্রুত গণনার মতো সুন্দর নয়, তবে এর মধ্যে একটি খুব আকর্ষণীয় বৈশিষ্ট্য রয়েছে: সমবর্তী গণনা। যদি গণনা ক্রমটি গুরুত্বপূর্ণ না হয় এবং লকিং ছাড়াই কাজগুলি সমান্তরালে করা যায়, এটি একটি মাল্টি-কোর সিস্টেমে যথেষ্ট গতিপথ সরবরাহ করতে পারে। একযোগে গণনা বিভাগে এটি সম্পর্কে আরও।

[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

দ্রুত গণনার পেছনের ধারণাটি হ'ল পুনরাবৃত্তিটি অনুকূল করতে দ্রুত সি অ্যারে অ্যাক্সেস ব্যবহার করা। এটি কেবল traditionalতিহ্যবাহী এনএসইউনিমরেটারের চেয়ে দ্রুত হওয়ার কথা নয়, তবে উদ্দেশ্য-সি ২.০ খুব সংক্ষিপ্ত বাক্য গঠনও সরবরাহ করে।

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

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

NSEnumerator

এটি বাহ্যিক পুনরাবৃত্তির একটি রূপ: [মাইআরাই অবজেক্টমেনামেটর] একটি অবজেক্ট ফেরত দেয়। এই অবজেক্টটির নেক্সট অবজেক্টের একটি পদ্ধতি রয়েছে যা আমরা কোনও লুপে কল করতে পারি যতক্ষণ না এটি শূন্য হয়

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

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

অবজেক্টএটিএন্ডেক্স: গণনা

লুপের জন্য এটি ব্যবহার করা যা একটি পূর্ণসংখ্যা বাড়ায় এবং [myArray অবজেক্টটিআইটিএনডেক্স: সূচক] ব্যবহার করে বস্তুকে জিজ্ঞাসা করা হয় এটি গণনার সর্বাধিক প্রাথমিক রূপ।

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

////////////// থেকে: অন্ধকার


11

তিনটি উপায়:

        //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. স্বতঃপূরণ সহ পুনরাবৃত্তি খাম লিখতে ভুলে যায়।


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
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.