8180

Is it possible to delete dictionary from mutablearray while iterating? [duplicate]

Question:

This question already has an answer here:

<ul><li> <a href="/questions/14471549/deleting-objects-within-a-for-loop-from-a-nsmutablearray" dir="ltr" rel="nofollow">Deleting objects within a for loop from a NSMutableArray</a> <span class="question-originals-answer-count"> 2 answers </span> </li> </ul> for (int i = 0; i< [optionDataArr count]; i++) { NSString *sName = [[optionDataArr objectAtIndex:i] objectForKey:kOptionName]; NSString *sPrice = [[optionDataArr objectAtIndex:i] objectForKey:kOptionExtraPrice]; if (sName.length == 0 && sPrice.length == 0) { [optionDataArr removeObjectAtIndex:i]; } }

Suppose optionDataArr contains a dictionary having no values and when above code executes i receive:

Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'

Answer1:

You can remove items when using a plain old for loop, you cannot when using fast enumeration.

Your code is buggy, though. When you delete the nth element, the next element will be (n+2)th. You need to manually decrement the index by one to account for the shifted elements.

Also keep in mind, that in this case you really need to do "real time" bounds checking of the array length in the loop, and not just use a temporary variable holding the length (or you need to decrement that one as well).

Answer2:

Below this line:

[optionDataArr removeObjectAtIndex:i];

add this line:

i--;

So, the code would be:

if (sName.length == 0 && sPrice.length == 0) { [optionDataArr removeObjectAtIndex:i]; i--; }

Reason: When you remove an item from an array while you are iterating on it, the indexes get changed. So, that's why you would need to manually decrement index.

Answer3:

Eiko answer is correct, but i wanted to show an other version using fast enumeration. You cannot remove items using fast enumeration, so you have do store the indexes and then remove the corresponding items later :

NSMutableIndexSet * indexesToRemove = [NSMutableIndexSet indexSet]; [optionDataArr enumerateObjectsUsingBlock:^(NSDictionary *dico, NSUInteger idx, BOOL *stop) { if ([dico count] == 0) [indexesToRemove addIndex:idx]; }]; [optionDataArr removeObjectsAtIndexes:indexesToRemove];

<strong>EDIT :</strong>

As Martin R sugested, you can also use indexesOfObjectsPassingTestmethod :

NSIndexSet * indexesToRemove = [optionDataArr indexesOfObjectsPassingTest:^BOOL(NSDictionary *dico, NSUInteger idx, BOOL *stop) { return ([dico count] == 0); }]; [optionDataArr removeObjectsAtIndexes:indexesToRemove];

Answer4:

You can certainly use a standard for loop for this, provided you make the modifications that Eiko has already mentioned.

However, the idomatic way to handle this in Objective C is to iterate over a copy of the array:

for (id obj in [optionDataArr copy]) { // some processing code if (condition) { [optionDataArr removeObject:obj] } }

While this does require a copy of the array, unless you know for sure that you are dealing with a significant amount of data, I would start with the readable version and optimise to the plain for loop when and if necessary.

Recommend

  • JsonConvert.DeserializeObject, Index was outside the bounds of the array
  • KoGrid JSON Dynamic widgets, with nested server calls
  • Cleave.js Phone CA
  • jQuery file download plugin
  • Drag and reorder - UICollectionview with sections
  • Understanding Intl.DateTimeFormat as a JavaScript object
  • How can I let users share their location in Bot Framework webchat channel?
  • C# - Most efficient way to iterate through multiple arrays/list
  • Consuming a WCF service in a Java Client using wsHttpBinding
  • HttpURLConnection Closing IO Streams
  • How to 'create temp table as select' in Slick?
  • Check all values in string[] for length?
  • ListItem.Attributes.Add not working
  • Parsing a CSV string while ignoring commas inside the individual columns
  • Jackson Parser: ignore deserializing for type mismatch
  • With Hadoop, can I create a tasktracker on a machine that isn't running a datanode?
  • Is there a way to do normal logging with EureakLog?
  • How to use remove-erase idiom for removing empty vectors in a vector?
  • Asynchronous UI Testing in Xcode With Swift
  • Repeat a vertical line on every page in Report Builder / SSRS
  • Why is an OPTIONS request sent to the server?
  • Regex thinks I'm nesting, but I'm not
  • What is the “return” in scheme?
  • How to convert from System.Drawing.Color to Excel.ColorFormat in C#? Change comment color
  • javascript inside java/jsp code
  • 'TypeError' while using NSGA2 to solve Multi-objective prob. from pyopt-sparse in OpenMDAO
  • Large data - storage and query
  • Rearranging Cells in UITableView Bug & Saving Changes
  • php design question - will a Helper help here?
  • SetUp method failed while running tests from teamcity
  • How to disable jQuery.jplayer autoplay?
  • Android Studio and gradle
  • Benchmarking RAM performance - UWP and C#
  • Angular 2 constructor injection vs direct access
  • What are the advantages and disadvantages of reading an entire file into a single String as opposed
  • IndexOutOfRangeException on multidimensional array despite using GetLength check
  • MATLAB: Piecewise function in curve fitting toolbox using fittype
  • How can i traverse a binary tree from right to left in java?
  • jQuery Masonry / Isotope and fluid images: Momentary overlap on window resize
  • How do I use LINQ to get all the Items that have a particular SubItem?