rib3ye
rib3ye

Reputation: 2923

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?

Upvotes: 13

Views: 8126

Answers (2)

Luca Angeletti
Luca Angeletti

Reputation: 59526

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.

Upvotes: 14

Marcus Rossel
Marcus Rossel

Reputation: 3268

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)
            }
        }
    }
}

Upvotes: 1

Related Questions