मैं एक NSArray पर पुनरावृति करने के लिए मानक मुहावरे की तलाश कर रहा हूं। मेरे कोड को OS X 10.4+ के लिए उपयुक्त होना चाहिए।
मैं एक NSArray पर पुनरावृति करने के लिए मानक मुहावरे की तलाश कर रहा हूं। मेरे कोड को OS X 10.4+ के लिए उपयुक्त होना चाहिए।
जवाबों:
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.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! :-)
for (id object in array)
, सरणी में वस्तुओं को वर्तमान सूचकांक का निर्धारण करने का एक तरीका है, या एक अलग काउंटर को शामिल करने की आवश्यकता है?
for
इस तरह एक लूप का उपयोग करता हूं :for(;;) { id object = [ e nextObject ] ; if ( !e ) { break ; } ... your loop operation ... }
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
}
for (NSUInteger i = 0, count = [myArray count]; i < count; i++)
संभवतः सबसे कुशल और संक्षिप्त है जिसे आप इस दृष्टिकोण के लिए प्राप्त करेंगे।
परीक्षण और स्रोत कोड के परिणाम नीचे हैं (आप ऐप में पुनरावृत्तियों की संख्या निर्धारित कर सकते हैं)। समय मिलीसेकंड में है, और प्रत्येक प्रविष्टि 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
तीन तरीके हैं:
//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
}];
each
अपने में विधि जोड़ें NSArray category
, आपको इसकी बहुत आवश्यकता है
ObjectiveSugar से लिया गया कोड
- (void)each:(void (^)(id object))block {
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
block(obj);
}];
}
स्विफ्ट के लिए
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
}
यह करो :-
for (id object in array)
{
// statement
}