पुनरावृत्ति करते समय NSMutableArray से निकालने का सबसे अच्छा तरीका?


194

कोको में, अगर मैं एक NSMutableArray के माध्यम से लूप करना चाहता हूं और एक निश्चित मानदंड को फिट करने वाली कई वस्तुओं को हटाता हूं, तो हर बार जब मैं किसी ऑब्जेक्ट को हटाता हूं तो लूप को पुनरारंभ किए बिना ऐसा करने का सबसे अच्छा तरीका क्या है?

धन्यवाद,

संपादित करें: बस स्पष्ट करने के लिए - मैं सबसे अच्छा तरीका ढूंढ रहा था, उदाहरण के लिए मैं जिस इंडेक्स पर हूं, उसे मैन्युअल रूप से अपडेट करने की तुलना में अधिक सुरुचिपूर्ण। उदाहरण के लिए C ++ में मैं कर सकता हूं;

iterator it = someList.begin();

while (it != someList.end())
{
    if (shouldRemove(it))   
        it = someList.erase(it);
}

9
पीछे से सामने की ओर लूप करें।
हॉट लक्स

कोई भी "WHY" का जवाब नहीं देता
onmyway133

1
@HotLicks मेरे सभी समय के पसंदीदा और प्रोग्रामिंग में सबसे कम आंकने वाले समाधान में से एक: D
जूलियन एफ। वेनर्ट

जवाबों:


388

स्पष्टता के लिए मैं एक प्रारंभिक लूप बनाना पसंद करता हूं जहां मैं हटाने के लिए आइटम एकत्र करता हूं। तब मैं उन्हें हटा देता हूं। यहाँ उद्देश्य-सी 2.0 सिंटैक्स का उपयोग कर एक नमूना दिया गया है:

NSMutableArray *discardedItems = [NSMutableArray array];

for (SomeObjectClass *item in originalArrayOfItems) {
    if ([item shouldBeDiscarded])
        [discardedItems addObject:item];
}

[originalArrayOfItems removeObjectsInArray:discardedItems];

फिर इस बारे में कोई सवाल नहीं है कि क्या सूचकांकों को सही ढंग से अपडेट किया जा रहा है, या अन्य छोटे बहीखाता विवरण।

जोड़ने के लिए संपादित:

यह अन्य उत्तरों में नोट किया गया है कि व्युत्क्रम सूत्रीकरण तेज होना चाहिए। यदि आप सरणी के माध्यम से पुनरावृत्ति करते हैं और वस्तुओं को छोड़ने के लिए रखने के बजाय वस्तुओं की एक नई सरणी बनाते हैं। यह सच हो सकता है (हालाँकि किसी नए ऐरे को आवंटित करने, और पुराने को त्यागने की स्मृति और प्रसंस्करण लागत के बारे में क्या?) लेकिन फिर भी अगर यह तेज़ है तो यह उतना बड़ा सौदा नहीं हो सकता है क्योंकि यह एक भोली कार्यान्वयन के लिए होगा, क्योंकि NSArrays "सामान्य" सरणियों की तरह व्यवहार न करें। वे बात करते हैं लेकिन वे एक अलग तरह से चलते हैं। एक अच्छा विश्लेषण यहाँ देखें:

उलटा सूत्रीकरण अधिक तेज़ हो सकता है, लेकिन मुझे यह ध्यान रखने की आवश्यकता नहीं है कि यह क्या है, क्योंकि उपरोक्त सूत्रीकरण हमेशा मेरी आवश्यकताओं के लिए पर्याप्त तेज़ रहा है।

मेरे लिए टेक-होम संदेश का उपयोग करना है जो भी सूत्रीकरण आपके लिए स्पष्ट है। यदि आवश्यक हो तो ही ऑप्टिमाइज़ करें। मैं व्यक्तिगत रूप से उपरोक्त सूत्रीकरण को स्पष्ट करता हूं, यही कारण है कि मैं इसका उपयोग करता हूं। लेकिन अगर उलटा सूत्र आपके लिए स्पष्ट है, तो इसके लिए जाएं।


47
खबरदार कि यह कीड़े पैदा कर सकता है अगर ऑब्जेक्ट किसी सरणी में एक से अधिक बार हैं। एक विकल्प के रूप में आप एक NSMutableIndexSet और - (void) removeObjectsAtIndexes का उपयोग कर सकते हैं।
जॉर्ज शॉली

1
यह वास्तव में उलटा करने के लिए तेज़ है। प्रदर्शन में अंतर बहुत बड़ा है, लेकिन अगर आपका सरणी इतना बड़ा नहीं है, तो समय या तो तुच्छ हो सकता है।
user1032657

मैंने रिवर्स का इस्तेमाल किया ... सरणी को शून्य के रूप में बनाया .. फिर केवल वही जोड़ा जो मुझे चाहिए था और डेटा को पुनः लोड किया ... किया ... डमी बनाया जो मुख्य सरणी का दर्पण है ताकि हमारे पास मुख्य वास्तविक डेटा हो
फ़हीम पारकर

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

82

एक और बदलाव। तो आपको पठनीयता और अच्छा प्रदर्शन मिलेगा:

NSMutableIndexSet *discardedItems = [NSMutableIndexSet indexSet];
SomeObjectClass *item;
NSUInteger index = 0;

for (item in originalArrayOfItems) {
    if ([item shouldBeDiscarded])
        [discardedItems addIndex:index];
    index++;
}

[originalArrayOfItems removeObjectsAtIndexes:discardedItems];

यह कमाल का है। मैं सरणी से कई आइटम निकालने की कोशिश कर रहा था और यह पूरी तरह से काम करता था। अन्य विधियाँ समस्याएँ पैदा कर रही थीं :) धन्यवाद आदमी
AbhinavVinay

कोरी, इस जवाब (नीचे) ने कहा कि, removeObjectsAtIndexesवस्तुओं को हटाने के लिए सबसे खराब तरीका है, क्या आप इससे सहमत हैं? मैं यह इसलिए पूछ रहा हूं क्योंकि आपका जवाब अभी बहुत पुराना है। फिर भी सबसे अच्छा चुनना अच्छा है?
हेमांग

पठनीयता की दृष्टि से यह समाधान मुझे बहुत पसंद है। @HotLicks उत्तर की तुलना में प्रदर्शन के मामले में यह कैसा है?
विक्टर माए एल्डेका

ओब्ज-सी में सरणी से वस्तुओं को हटाते समय इस पद्धति को निश्चित रूप से प्रोत्साहित किया जाना चाहिए।
बोरियास

enumerateObjectsUsingBlock:आपको मुफ्त में सूचकांक वृद्धि मिलेगी।
पीकेएम

42

यह एक बहुत ही साधारण समस्या है। आप बस पीछे की ओर पुनरावृति करें:

for (NSInteger i = array.count - 1; i >= 0; i--) {
   ElementType* element = array[i];
   if ([element shouldBeRemoved]) {
       [array removeObjectAtIndex:i];
   }
}

यह एक बहुत ही सामान्य पैटर्न है।


जेन्स उत्तर याद होगा,
क्यूज़

3
यह सबसे अच्छी विधि है। यह याद रखना महत्वपूर्ण है कि पुनरावृत्ति चर एक हस्ताक्षरित होना चाहिए, इसके बावजूद कि उद्देश्य-सी में सरणी सूचकांकों को अहस्ताक्षरित घोषित किया गया है (मैं कल्पना कर सकता हूं कि Apple को अब कैसे पछतावा है)।
मोजुबा

39

अन्य जवाबों में से कुछ में बहुत बड़े सरणियों पर खराब प्रदर्शन होगा, क्योंकि रिसीवर की रैखिक खोज करने के तरीके removeObject:और removeObjectsInArray:शामिल करने के तरीके , जो एक बेकार है क्योंकि आप पहले से ही जानते हैं कि ऑब्जेक्ट कहां है। इसके अलावा, किसी भी कॉल को removeObjectAtIndex:एक समय में एक स्लॉट द्वारा इंडेक्स से सरणी के अंत तक मान कॉपी करना होगा।

अधिक कुशल निम्नलिखित होगा:

NSMutableArray *array = ...
NSMutableArray *itemsToKeep = [NSMutableArray arrayWithCapacity:[array count]];
for (id object in array) {
    if (! shouldRemove(object)) {
        [itemsToKeep addObject:object];
    }
}
[array setArray:itemsToKeep];

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

[array release];
array = [itemsToKeep retain];

इसलिए मूल्यों को कॉपी करने की भी आवश्यकता नहीं है, केवल एक पॉइंटर स्वैप करें।


यह जटिलता समय की जटिलता के संदर्भ में अच्छी साबित होती है। मैं इसे अंतरिक्ष जटिलता के संदर्भ में समझने की कोशिश कर रहा हूं। मेरे पास एक ही कार्यान्वयन है, जहां मैं वास्तविक 'एरियर काउंट' के साथ 'itemsToKeep' की क्षमता निर्धारित करता हूं। लेकिन कहते हैं कि मैं कुछ वस्तुओं को सरणी से नहीं चाहता, इसलिए मैं इसे आइटमटॉक में नहीं जोड़ता। तो मेरी वस्तुओं की क्षमता 10 किलो है, लेकिन मैं वास्तव में इसमें केवल 6 वस्तुओं को संग्रहीत करता हूं। क्या इसका मतलब है कि मैं 4 वस्तुओं का स्थान बर्बाद कर रहा हूं? पीएस को दोष नहीं मिल रहा है, बस एल्गो जटिलता को समझने की कोशिश कर रहा है। :)
Tech_human

हां, आपके पास चार पॉइंट के लिए स्पेस आरक्षित है जिसका आप उपयोग नहीं कर रहे हैं। ध्यान रखें कि सरणी में केवल पॉइंटर्स होते हैं, न कि ऑब्जेक्ट्स स्वयं, इसलिए चार ऑब्जेक्ट्स के लिए जिसका अर्थ है 16 बाइट्स (32 बिट आर्किटेक्चर) या 32 बाइट्स (64 बिट)।
बेंज़ादो

ध्यान दें कि किसी भी समाधान के लिए 0 अतिरिक्त स्थान की आवश्यकता होती है (आप आइटम को जगह में हटाते हैं) या मूल सरणी आकार को सबसे खराब रूप से दोगुना करते हैं (क्योंकि आप सरणी की प्रतिलिपि बनाते हैं)। फिर से, क्योंकि हम संकेत और वस्तुओं की पूरी प्रतियों के साथ काम कर रहे हैं, यह ज्यादातर परिस्थितियों में बहुत सस्ता है।
बेन्जादो

ठीक है समझ आ गया। धन्यवाद बेंजादो !!
Tech_human

इस पोस्ट के अनुसार , arrayWithCapacity का संकेत: सरणी के आकार के बारे में विधि वास्तव में उपयोग नहीं की जा रही है।
कर्मक

28

आप अपने उत्परिवर्तित सरणी से आइटम निकालने के लिए NSpredicate का उपयोग कर सकते हैं। इसके लिए छोरों की आवश्यकता नहीं है।

उदाहरण के लिए यदि आपके पास नामों की NSMutableArray है, तो आप इस तरह एक विधेय बना सकते हैं:

NSPredicate *caseInsensitiveBNames = 
[NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"];

निम्नलिखित पंक्ति आपको एक सरणी के साथ छोड़ देगी जिसमें केवल बी के साथ शुरू होने वाले नाम हैं।

[namesArray filterUsingPredicate:caseInsensitiveBNames];

यदि आपको अपनी ज़रूरत के अनुसार विधेय बनाने में परेशानी होती है, तो इस ऐप्पल डेवलपर लिंक का उपयोग करें ।


3
छोरों के लिए कोई दृश्यमान की आवश्यकता नहीं है । फ़िल्टर ऑपरेशन में एक लूप होता है, आप इसे नहीं देखते हैं।
हॉट लिक्स

18

मैंने 4 अलग-अलग तरीकों का उपयोग करके एक प्रदर्शन परीक्षण किया। प्रत्येक परीक्षण 100,000 तत्व सरणी में सभी तत्वों के माध्यम से पुनरावृत्त होता है, और हर 5 वें आइटम को हटा दिया जाता है। परिणाम अनुकूलन के साथ / बिना भिन्न नहीं हुए। ये एक iPad 4 पर किया गया था:

(1) removeObjectAtIndex:- 271 एमएस

(2) removeObjectsAtIndexes:- 1010 एमएस (क्योंकि इंडेक्स सेट के निर्माण में ~ 700 एमएस लगता है, अन्यथा यह मूल रूप से कॉलिंग रिमूव के समान है। विशेषांक: प्रत्येक आइटम के लिए)

(३) removeObjects:- ३२६ मि

(4) परीक्षण पास करने वाली वस्तुओं के साथ एक नया सरणी बनाएं - 17 एमएस

तो, एक नई सरणी बनाना अब तक का सबसे तेज़ है। अन्य तरीके सभी तुलनीय हैं, सिवाय इसके कि रिमूव को हटाते हुए।


1
क्या आपने एक नई सरणी बनाने के लिए समय गिना और बाद में उसे निपटाया। मुझे विश्वास नहीं है कि यह अकेले 17 एमएस में कर सकता है। प्लस 75,000 असाइनमेंट?
जैक

एक नई व्यूह
रचना

आपने स्पष्ट रूप से रिवर्स लूप योजना नहीं मापी।
हॉट लिक्स

पहला परीक्षण रिवर्स लूप योजना के बराबर है।
user1032657

क्या होता है जब आप अपने newArray के साथ छोड़ दिए जाते हैं, और आपका प्रचलित नाम Nulled होता है? आपको newArray को कॉपी करना होगा कि PrevArray को क्या नाम दिया गया था (या इसका नाम बदलें) अन्यथा आपका अन्य कोड इसे कैसे संदर्भित करेगा?
aremvee

17

या तो सूचकांकों पर लूप काउंटिंग का उपयोग करें:

for (NSInteger i = array.count - 1; i >= 0; --i) {

या जिन वस्तुओं को आप रखना चाहते हैं, उनके साथ एक प्रति बनाएँ।

विशेष रूप से, एक for (id object in array)लूप का उपयोग न करें या NSEnumerator


3
आपको अपना उत्तर कोड m8 में लिखना चाहिए। हाहा लगभग छूट गया।
फ्लोयू। SimpleUITesting.com

यह सही नहीं है। "(आईडी ऑब्जेक्ट में सरणी)" के लिए "NSInteger i = array.count - 1 =>> = =; --i) से अधिक तेज़ है, और इसे तेज़ पुनरावृत्ति कहा जाता है। सूचक का उपयोग करना निश्चित रूप से अनुक्रमण से तेज है।
जैक

@jack - लेकिन अगर आप एक इटैलर के नीचे से एक तत्व निकालते हैं तो आप आमतौर पर कहर पैदा करते हैं। (और "तेज़ पुनरावृत्ति" हमेशा उतना तेज़ नहीं होता है।)
हॉट लिक्स

जवाब 2008 से है। तेजी से चलना मौजूद नहीं था।
जेन्स आयटन

12

IOS 4+ या OS X 10.6+ के लिए, Apple ने passingTestइसमें API की श्रृंखला जोड़ी NSMutableArray, जैसे – indexesOfObjectsPassingTest:। ऐसे एपीआई के साथ एक समाधान होगा:

NSIndexSet *indexesToBeRemoved = [someList indexesOfObjectsPassingTest:
    ^BOOL(id obj, NSUInteger idx, BOOL *stop) {
    return [self shouldRemove:obj];
}];
[someList removeObjectsAtIndexes:indexesToBeRemoved];

12

आजकल आप उल्टे ब्लॉक-आधारित गणना का उपयोग कर सकते हैं। एक सरल उदाहरण कोड:

NSMutableArray *array = [@[@{@"name": @"a", @"shouldDelete": @(YES)},
                           @{@"name": @"b", @"shouldDelete": @(NO)},
                           @{@"name": @"c", @"shouldDelete": @(YES)},
                           @{@"name": @"d", @"shouldDelete": @(NO)}] mutableCopy];

[array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    if([obj[@"shouldDelete"] boolValue])
        [array removeObjectAtIndex:idx];
}];

परिणाम:

(
    {
        name = b;
        shouldDelete = 0;
    },
    {
        name = d;
        shouldDelete = 0;
    }
)

कोड की सिर्फ एक पंक्ति के साथ एक और विकल्प:

[array filterUsingPredicate:[NSPredicate predicateWithFormat:@"shouldDelete == NO"]];

क्या इस बात की कोई गारंटी है कि सरणी को पुनः प्राप्त नहीं किया जाएगा?
Cfr

क्या आप reallocation के साथ क्या मतलब है?
वाइकिंगोजगंडो

रेखीय संरचना से तत्व को हटाते समय यह नए सन्निहित मेमोरी ब्लॉक को आवंटित करने और वहां सभी तत्वों को स्थानांतरित करने के लिए प्रभावी हो सकता है। इस स्थिति में सभी संकेत अमान्य हो जाएंगे।
9

चूंकि विलोपन कार्रवाई को नहीं पता होगा कि अंत में कितने तत्व हटाए जाएंगे, यह हटाने के दौरान ऐसा करने का कोई मतलब नहीं है। वैसे भी: कार्यान्वयन विस्तार, w को उचित कोड लिखने के लिए सेब पर भरोसा करना होगा।
vikingosegundo

पहला अच्छा नहीं है (क्योंकि आपको इस बारे में बहुत सोचना है कि यह पहली जगह में कैसे काम करता है) और दूसरा सुरक्षित नहीं है। इसलिए अंत में मैंने क्लासिक स्वीकृत समाधान के साथ समाप्त किया जो वास्तव में काफी पठनीय है।
रेनिटिक

8

अधिक घोषणात्मक तरीके से, आपके द्वारा उपयोग की जा सकने वाली वस्तुओं से मेल खाने वाले मानदंडों के आधार पर:

[theArray filterUsingPredicate:aPredicate]

@ नथन बहुत कुशल होना चाहिए


6

यहाँ आसान और साफ तरीका है। मुझे तेजी से एन्यूमरेशन कॉल में अपने एरे को डुप्लिकेट करना पसंद है:

for (LineItem *item in [NSArray arrayWithArray:self.lineItems]) 
{
    if ([item.toBeRemoved boolValue] == YES) 
    {
        [self.lineItems removeObject:item];
    }
}

इस तरह आप एक ही ऑब्जेक्ट पकड़े हुए दोनों से हटाए जा रहे एरे की कॉपी के माध्यम से गणना करते हैं। एक NSArray ऑब्जेक्ट पॉइंटर्स रखता है, इसलिए यह पूरी तरह से ठीक मेमोरी / प्रदर्शन वार है।


2
या उससे भी सरल -for (LineItem *item in self.lineItems.copy)
अलेक्जेंड्रे जी

5

उन वस्तुओं को जोड़ें जिन्हें आप दूसरे सरणी में निकालना चाहते हैं और, लूप के बाद, -removeObjectsInArray का उपयोग करें।


5

यह करना चाहिए:

    NSMutableArray* myArray = ....;

    int i;
    for(i=0; i<[myArray count]; i++) {
        id element = [myArray objectAtIndex:i];
        if(element == ...) {
            [myArray removeObjectAtIndex:i];
            i--;
        }
    }

उम्मीद है की यह मदद करेगा...


हालांकि अपरंपरागत, मैं पीछे की ओर पुनरावृत्त पाया और हटाने के रूप में मैं एक स्वच्छ और सरल समाधान हो जाना है। आमतौर पर सबसे तेज़ तरीकों में से एक।
रैपेट्रीक

इसमें गलत क्या है? यह साफ, तेज, आसानी से पढ़ने योग्य है, और यह एक आकर्षण की तरह काम करता है। मेरे लिए यह सबसे अच्छा जवाब लगता है। इसका नकारात्मक अंक क्यों है? क्या मुझसे कोई चूक हो रही है?
स्टीफ थिरियन

1
@Steph: प्रश्न "सूचकांक को मैन्युअल रूप से अपडेट करने की तुलना में कुछ अधिक सुरुचिपूर्ण है।"
स्टीव मैडसेन

1
ओह। मुझे आई-बिल्कुल-न-टू-अपडेट-टू-द-इंडेक्स-मैन्युअल रूप से भाग की याद आती थी। धन्यवाद स्टीव। IMO यह समाधान चुने हुए (कोई अस्थायी सरणी की आवश्यकता) की तुलना में अधिक सुरुचिपूर्ण नहीं है, इसलिए इसके खिलाफ नकारात्मक वोट अनुचित लगता है।
स्टीफ थिरियन

@Steve: यदि आप संपादन की जांच करते हैं, तो मैं अपना जवाब प्रस्तुत करने के बाद वह भाग जोड़ दिया गया था .... यदि नहीं, तो मैंने "पीछे की ओर इशारा करते हुए" सबसे सुरुचिपूर्ण समाधान के साथ उत्तर दिया होगा :)। आपका दिन शुभ हो!
पोकॉट0

1

आप ऑब्जेक्ट्स को किसी अन्य NSMutableArray में निकालने के लिए क्यों नहीं जोड़ते हैं। जब आप पुनरावृत्ति समाप्त कर लेते हैं, तो आप उन वस्तुओं को हटा सकते हैं जिन्हें आपने एकत्र किया है।


1

उन तत्वों की अदला-बदली के बारे में जिन्हें आप 'n'th एलिमेंट,' n-1'th एलीमेंट आदि से हटाना चाहते हैं?

जब आप कर लेते हैं तो आप सरणी को 'पिछले आकार - स्वैप की संख्या' का आकार बदल देते हैं


1

यदि आपके एरे में सभी ऑब्जेक्ट अद्वितीय हैं या आप किसी ऑब्जेक्ट के पाए जाने पर उसे हटाना चाहते हैं, तो आप किसी सरणी कॉपी पर तेजी से एन्यूमरेट कर सकते हैं और ऑरिजनल से ऑब्जेक्ट को हटाने के लिए [NSMutableArray removeObject:] का उपयोग कर सकते हैं।

NSMutableArray *myArray;
NSArray *myArrayCopy = [NSArray arrayWithArray:myArray];

for (NSObject *anObject in myArrayCopy) {
    if (shouldRemove(anObject)) {
        [myArray removeObject:anObject];
    }
}

यदि निष्पादित होने के दौरान मूल myArray अपडेट हो जाता है तो क्या होगा +arrayWithArray?
बॉयोफे

1
@ नीफ़े: फिर आपके पास अपने कोड में एक बग है। NSMutableArray थ्रेड-सुरक्षित नहीं है, आपको ताले के माध्यम से पहुंच को नियंत्रित करने की उम्मीद है। इसका उत्तर
ड्रीमलैक्स 28'13

1

ऊपर बेंज़ादो के एवेज़र है जो आपको प्रीफॉर्म के लिए करना चाहिए। मेरे अनुप्रयोगों में से एक में removeObjectsInArray ने 1 मिनट का समय लिया, बस एक नई सरणी को जोड़ने में .023 सेकंड लगे।


1

मैं एक श्रेणी को परिभाषित करता हूं, जो मुझे एक ब्लॉक का उपयोग करके फ़िल्टर करने देता है, जैसे:

@implementation NSMutableArray (Filtering)

- (void)filterUsingTest:(BOOL (^)(id obj, NSUInteger idx))predicate {
    NSMutableIndexSet *indexesFailingTest = [[NSMutableIndexSet alloc] init];

    NSUInteger index = 0;
    for (id object in self) {
        if (!predicate(object, index)) {
            [indexesFailingTest addIndex:index];
        }
        ++index;
    }
    [self removeObjectsAtIndexes:indexesFailingTest];

    [indexesFailingTest release];
}

@end

जो तब इस तरह इस्तेमाल किया जा सकता है:

[myMutableArray filterUsingTest:^BOOL(id obj, NSUInteger idx) {
    return [self doIWantToKeepThisObject:obj atIndex:idx];
}];

1

NSMutableArray पर नीचे श्रेणी विधि का उपयोग करने के लिए एक अच्छा कार्यान्वयन हो सकता है।

@implementation NSMutableArray(BMCommons)

- (void)removeObjectsWithPredicate:(BOOL (^)(id obj))predicate {
    if (predicate != nil) {
        NSMutableArray *newArray = [[NSMutableArray alloc] initWithCapacity:self.count];
        for (id obj in self) {
            BOOL shouldRemove = predicate(obj);
            if (!shouldRemove) {
                [newArray addObject:obj];
            }
        }
        [self setArray:newArray];
    }
}

@end

सरणी में प्रत्येक ऑब्जेक्ट पर प्रसंस्करण करने के लिए विधेय ब्लॉक को लागू किया जा सकता है। यदि विधेय सही है तो वस्तु हटा दी जाती है।

पूर्व में पड़े सभी तिथियों को हटाने के लिए दिनांक सरणी के लिए एक उदाहरण:

NSMutableArray *dates = ...;
[dates removeObjectsWithPredicate:^BOOL(id obj) {
    NSDate *date = (NSDate *)obj;
    return [date timeIntervalSinceNow] < 0;
}];

0

बैकवर्ड-लिटर को इरिटेट करना वर्षों से मेरा पसंदीदा था, लेकिन लंबे समय तक मुझे कभी भी इस मामले का सामना नहीं करना पड़ा जहां 'सबसे गहरी' (उच्चतम गिनती) वस्तु को पहले हटा दिया गया था। इससे पहले कि पॉइंटर अगले सूचकांक पर आगे बढ़े, वहाँ कुछ भी नहीं है और यह दुर्घटनाग्रस्त हो जाता है।

बेंज़ादो का रास्ता अब मैं जो भी करता हूं उसके सबसे करीब है, लेकिन मुझे कभी भी एहसास नहीं हुआ कि हर हटाने के बाद स्टैक फेरबदल होगा।

Xcode 6 के तहत यह काम करता है

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

    for (id object in array)
    {
        if ( [object isNotEqualTo:@"whatever"]) {
           [itemsToKeep addObject:object ];
        }
    }
    array = nil;
    array = [[NSMutableArray alloc]initWithArray:itemsToKeep];
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.