Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I safely remove items from an array in a for loop?

Full disclose, this is for a homework question:

It should have a private property of type [Circle]. An array of circles. The method should remove any circles that have a radius larger than the minimum requirement, and smaller than the max requirement.

It seems obvious that I should use removeAtIndex() to remove array items that don't meet a condition determined in the loop. However, many have pointed out before the perils of removing items in a loop because of what I guess is a "iterator/index mismatch".

Ultimately I ended up creating an empty array and using .append() to push the values that meet the "good" condition to a filteredCircles array, but I can't help but to feel that this this doesn't meet the criteria for the assignment.

Is there a solution that actually removes the items from the array in a loop?

like image 558
nipponese Avatar asked Jan 30 '16 11:01

nipponese


People also ask

How do you remove an element from an array loop?

Use unset() function to remove array elements in a foreach loop. The unset() function is an inbuilt function in PHP which is used to unset a specified variable. The behavior of this function depends on different things.

Which method is used to remove an element from the array?

To remove the element from a specific index position, the splice() method is used. It removes the element from a specific position and returns that removed element. It also allows the users to remove one or more elements from the array.


2 Answers

If the FOR LOOP is not mandatory (and I don't see this requirement in the quoted text) you should use the filter method.

When you invoke filter on an array you get a new array containing only the values that do respect the closure you passed to filter. The original array is not mutated.

struct Circle {
    let radius: Double
}

let circles = [Circle(radius: 1), Circle(radius: 5.1), Circle(radius: 4), Circle(radius: 10.8)]

let bigCircles = circles.filter { $0.radius > 5 }

Why this approach is better than mutating the array in a FOR LOOP

  1. Since circles is a constant, you don't have problems related to multithreading programming. If circles was mutable then other threads could change it while you are looping it with very scary side effects.
  2. It's less error prone. You are not writing what the CPU should do, instead you are describing how the results should be. So less potential misunderstandings between you and the compiler :)
  3. You are writing less code which does mean less potential mistakes.

These are some of the benefits of writing Functional Programming code.

like image 178
Luca Angeletti Avatar answered Oct 06 '22 16:10

Luca Angeletti


To elaborate in @vacawama's answer:

struct Circle {
    var radius: Int
}

struct MyStruct {
    private var circles: [Circle]

    mutating func removeCirclesWithRadiusWithin(range: Range<Int>) {
        for index in (circles.startIndex..<circles.endIndex).reverse() {
            if range.contains(circles[index].radius) {
                circles.removeAtIndex(index)
            }
        }
    }
}

If you want to use Double for your Circle's radius, but want to keep the nice syntax:

struct Circle {
    var radius: Double
}

struct MyStruct {
    private var circles: [Circle]

    mutating func removeCirclesWithRadiusWithin<I: IntervalType where I.Bound == Double>(interval: I) {
        for index in (circles.startIndex..<circles.endIndex).reverse() {
            if interval.contains(circles[index].radius) {
                circles.removeAtIndex(index)
            }
        }
    }
}
like image 42
Marcus Rossel Avatar answered Oct 06 '22 18:10

Marcus Rossel