Selectively delete and delete objects from NSMutableArray in Swift

The main question. What is the best way to selectively remove and remove elements from a mutable array in Swift?

There are options that are NOT suitable for this, for example, calling removeObject inside

  • for the cycle
  • enumeration block

and others that seem to work generally like

  • for the loop using index + call removeObjectAtIndex , even inside the loop
  • for a loop to populate an array withithItemsToRemove, and then use originalArray. removeObjectsInArray (arrayWithItemsToRemove)
  • using .filter to create a new array seems really nice, but I'm not quite sure how I feel about replacing the entire original array

Is there a recommended, easy, and safe way to remove elements from an array? One of those that I mentioned or is missing something?

It would be nice to get different options (with pluses and minuses) or preferences about this. I'm still trying to choose the right one.

+5
source share
3 answers

If you want to cyclically remove elements from NSMutableArray based on the condition, you can encode the array in reverse order (from the last index to zero) and delete objects that satisfy the condition.

For example, if you have an array of integers and you want to remove numbers divisible by three, you can start the loop as follows:

 var array: NSMutableArray = [1, 2, 3, 4, 5, 6, 7]; for index in stride(from: array.count - 1, through: 0, by: -1) { if array[index] as Int % 3 == 0 { array.removeObjectAtIndex(index) } } 

Quoting in the reverse order ensures that the index of the elements of the array that remains to be verified does not change. Instead, in direct mode, if you delete, for example, the first element, then the element preceding index 1 will change to index 0, and you will have to take this into account in the code.

Using removeObject (which does not work with the above code) is not recommended in a loop for performance reasons, because its implementation goes through all the elements of the array and uses isEqualTo to determine whether to remove the object or not. The complexity order rises from O (n) to O (n ^ 2) - in the worst case, when all elements of the array are deleted, the array passes once in the main loop and crosses the array for each element again. Therefore, all decisions based on enumeration blocks, for-in , etc., should be avoided unless you have a good reason.

filter instead is a good alternative, and this is what I will use because:

  • it is concise and clear: 1 line of code as opposed to 5 lines (including closing brackets) for index-based solution
  • its characteristics are comparable to an index-based solution - it is a bit slower, but I think not so much.

This may not be ideal in all cases, because, as you said, it generates a new array, and does not work in place.

+11
source

When working with NSMutableArray, you should not delete objects while you loop through the most mutable array (unless you loop back, as Antonio pointed out).

The general solution is to make an immutable copy of the array, iterate over the copy and selectively delete the objects in the original mutable array by calling removeObject or calling removeObjectAtIndex, but you will need to calculate the index since the indices in the original array and the copy will not match due to deletion (you will have to decrease the โ€œdeletion indexโ€ every time the object is deleted).

Another solution (better) is to loop the array once, create an NSIndexSet with the indices of the objects to remove, and then call "removeObjectsAtIndexes:" on the mutable array.

See the NSMutableArray "removeObjectsAtIndexes:" documentation in Swift .

+7
source

Some options:

  • For loops over indexes and calling removeObjectAtIndex : 1) You will have to deal with the fact that when you delete the index of the next object will become the current index, so you should not increase the index in this case; you can avoid this by iterating backwards. 2) Each call to removeObjectAtIndex is O (n) (since it should move all subsequent elements forward), so the algorithm is O (n ^ 2).
  • For a loop, build a set of elements to remove, and then call removeObjectsInArray : the first part is O (n). removeObjectsInArray uses a hash table to efficiently test items for removal; the hash table is O (1) on average, but O (n) in the worst case, so the O (n) algorithm is on average, but O (n ^ 2) in the worst case.
  • Using filter to create a new array: this is O (n). It creates a new array.
  • For the loop to create an index set of element indices to remove (or using indexesOfObjectsPassingTest ), then delete them with removeObjectsAtIndexes : I believe this is O (n). It does not create a new array.
  • Use filterUsingPredicate , using a predicate based on the block of your test: I believe this is also O (n). It does not create a new array.
+4
source

Source: https://habr.com/ru/post/1201964/


All Articles