如何安全地从for循环中的数组中删除项?

时间:2022-03-08 23:07:15

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.

它应该具有类型为[Circle]的私有属性。圈的数组。该方法去除半径大于最小要求、小于最大要求的圆。

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".

显然,我应该使用removeAtIndex()删除不满足循环中确定的条件的数组项。然而,在删除循环中的项之前,许多人已经指出,因为我猜是“迭代器/索引不匹配”。

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.

最终,我创建了一个空数组,并使用.append()来将满足“良好”条件的值推到filteredCircles数组中,但我不得不感到,这并不符合赋值的标准。

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

是否有一个解决方案可以在循环中从数组中删除项?

2 个解决方案

#1


9  

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

如果FOR循环不是强制性的(我在引用的文本中没有看到这个要求),您应该使用filter方法。

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. 因为圆是常量,所以您不会遇到与多线程编程相关的问题。如果圆圈是可变的,那么其他线程可以在循环时更改它,这会产生非常可怕的副作用。
  3. 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 :)
  4. 这是不容易出错。您不是在编写CPU应该做什么,而是在描述结果应该如何。这样你和编译器之间的潜在误解就会减少
  5. You are writing less code which does mean less potential mistakes.
  6. 你写的代码更少了,这意味着更少的潜在错误。

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

这是编写函数式编程代码的一些好处。

#2


1  

To elaborate in @vacawama's answer:

在@vacawama的回答中详述:

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:

如果你想用Double表示你的圆的半径,但是想要保持漂亮的语法:

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

#1


9  

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

如果FOR循环不是强制性的(我在引用的文本中没有看到这个要求),您应该使用filter方法。

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. 因为圆是常量,所以您不会遇到与多线程编程相关的问题。如果圆圈是可变的,那么其他线程可以在循环时更改它,这会产生非常可怕的副作用。
  3. 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 :)
  4. 这是不容易出错。您不是在编写CPU应该做什么,而是在描述结果应该如何。这样你和编译器之间的潜在误解就会减少
  5. You are writing less code which does mean less potential mistakes.
  6. 你写的代码更少了,这意味着更少的潜在错误。

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

这是编写函数式编程代码的一些好处。

#2


1  

To elaborate in @vacawama's answer:

在@vacawama的回答中详述:

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:

如果你想用Double表示你的圆的半径,但是想要保持漂亮的语法:

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