如何根据另一个数组从数组中删除数据?

时间:2016-07-22 14:54:42

标签: arrays swift

let guideArray = ["TRUE", "TRUE", "TRUE", "FALSE", "TRUE", "TRUE", "FALSE"]
let toBeRemoved = ["ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN"]

我想删除根据索引对FALSE的值。

操作后输出应如下:

toBeRemoved = ["ONE", "TWO", "THREE", "FIVE", "SIX"]
//Forth and seventh element deleted

我尝试使用for-in循环,如下所示,但由于每次运行数组计数更改而失败。

for i in 0...(guideArray.count-1) {
  if guideArray[i] == "FALSE"{
    toBeRemoved.removeAtIndex(i) 
    //this failed because of every time it runs toBeRemoved.count integer changes
  }
}

3 个答案:

答案 0 :(得分:4)

解决方案

这是函数式编程非常有用的问题。

鉴于这两个阵列

let words = ["ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN"]
let shouldRemove = ["TRUE", "TRUE", "TRUE", "FALSE", "TRUE", "TRUE", "FALSE"]

您可以通过这种方式执行过滤

let filtered = zip(words, shouldRemove).filter { $0.1 == "TRUE" }.map { $0.0 }
// ["ONE", "TWO", "THREE", "FIVE", "SIX"]

它是如何工作的?

zip(words, shouldRemove)
  

这创建了一个序列,其中第一个数组的第n个元素与第二个数组的第n个元素配对。因此,此序列的每个元素都有2个组件(一个来自words,另一个来自shouldRemove)。

zip(words, shouldRemove)
---------| ---------
ONE      | TRUE
---------| ---------
TWO      | TRUE
---------| ---------
THREE    | TRUE
---------| ---------
FOUR     | FALSE
---------| ---------
FIVE     | TRUE
---------| ---------
SIX      | TRUE
---------| ---------
SEVEN    | FALSE
---------| ---------

下一步

.filter { $0.1 == "TRUE" }
  

这会过滤序列,只留下第二个成分是字符串“TRUE”的元素

---------| ---------
ONE      | TRUE
---------| ---------
TWO      | TRUE
---------| ---------
THREE    | TRUE
---------| ---------
FIVE     | TRUE
---------| ---------
SIX      | TRUE
---------| ---------

下一步

.map { $0.0 }
  

最后,对于每个元素,只返回第一个组件(来自words的那个)。

---------
ONE      
---------
TWO
---------
THREE
---------
FIVE 
---------
SIX 
---------

为什么要重命名数组的名称?

  • 在Swift中,我们不会将变量的类型用于它的名称。变量的名称应该代表它的值。
  • 数组的名称已反转。您使用内容命名toBeRemoved数组。它不应该是"TRUE"/"FALSE"的名称吗?

答案 1 :(得分:3)

您可以从最后一个索引开始计数到第一个索引,而不是从第一个索引开始并计数到最后一个索引。如果你从一个数组中删除一个元素,它只会在它之后移动它,所以通过倒计时,你可以确保你仍然需要影响的元素没有通过移除前面的元素来移动。

在您的示例中,您尝试从索引0开始并计数到索引6.这意味着当您到达数组中的第四个元素并将其删除时,您需要迭代的其余元素向前移动一个空间,这是导致您的问题。

在您的情况下,此代码将从索引6开始,即最后一个索引,并查看是否应删除该索引。它应该被删除,所以你将删除它。然后你将转到索引5,它仍然是“SIX”,因为从末尾删除“SEVEN”并没有改变它之前元素的顺序。

for i in (guideArray.count - 1).stride(through: 0, by: -1) {
    if guideArray[i] == "FALSE"{
        toBeRemoved.removeAtIndex(i)
    }
}

答案 2 :(得分:3)

另一种解决方案,没有拉链/循环:

let guideArray = ["TRUE", "TRUE", "TRUE", "FALSE", "TRUE", "TRUE", "FALSE"]
let toBeRemoved = ["ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN"]

let resultArray = guideArray.enumerate().flatMap{$0.element == "TRUE" ? toBeRemoved[$0.index] : nil}

print(resultArray)
// ["ONE", "TWO", "THREE", "FIVE", "SIX"]

这里我们通过在" FALSE"中用nil替换元素来平滑映射toBeRemoved数组。位置