Swift根据另一个布尔数组过滤其他数组

4

我有一个布尔数组,想要编辑分数数组和日期数组中与FALSE相对应的值。我无法实现它。我想过获取为FALSE的元素并使用该数组将这些元素从分数数组中删除,但我可以想象有一种直接的方法来完成它。

let hbiCompleteArray = [true, true, true, true, false, true, true, false, false]

let hbiScoreArray = [12, 12, 12, 12, 3, 13, 13, 2, 2]

我想要一个完整Hbi分数的数组 = [12, 12, 12, 12, 13, 13]。

3
考虑使用一个自定义结构体的数组来代替多个数组作为模型的数据存储方式。 - vadian
哦,那听起来超酷的,我该怎么做呢? - SashaZ
4个回答

6
如果你必须使用两个数组,你可以用 zipfiltermap 来解决这个问题,像这样:
let hbiCompleteArray = [true, true, true, true, false, true, true, false, false]
let hbiScoreArray = [12, 12, 12, 12, 3, 13, 13, 2, 2]

let result = zip(hbiCompleteArray, hbiScoreArray).filter { $0.0 }.map { $1 }
print(result)

给出:

[12, 12, 12, 12, 13, 13]

解释: zip将两个数组交错(创建一个(Bool, Int)元组的数组),然后filter { $0.0 }仅保留true布尔值,然后map仅保留Int值。


以前从未见过 zip - mfaani
1
@ColGraff 确实会迭代多次,但我认为这不是问题,甚至不是一个关注点。我们可以猜测 OP 的数组中不会有数十亿个分数 - 另外,Zip2Sequence 的性质(不是实际的数组)以及 filter/map 被优化(缓冲区、写时复制、编译器优化等)使我认为这在这里真的没问题。 :) - Eric Aya
1
我同意这可能不是一个问题,如果没有测试瓶颈就切换到另一个解决方案肯定是过早的优化。使用这个解决方案是因为它简单明了,如果测试显示它是一个瓶颈,那么再进行优化。这应该是大多数软件开发的指导方针! - user887210
1
请注意,您也可以使用 flatMap 而不是 filtermap,例如 let result = zip(hbiCompleteArray, hbiScoreArray).flatMap {$0 ? $1 : nil} :) - Hamish
1
运行良好,非常优雅。现在尝试使用相同的方法返回日期数组。谢谢。 - SashaZ
显示剩余5条评论

5

vadian的评论在这里非常重要。你不应该以这种方式拥有多个数组。创建一个包含数据的结构体:

struct Score {
    let isComplete: Bool
    let finalScore: Int
}

您可以添加日期或您目前有平行数组的其他字段。然后,您的数据如下所示:
let scores = [
    Score(isComplete: true, finalScore: 12),
    Score(isComplete: true, finalScore: 12),
    Score(isComplete: true, finalScore: 12),
    Score(isComplete: true, finalScore: 12),
    Score(isComplete: false, finalScore: 3),
    Score(isComplete: true, finalScore: 13),
    Score(isComplete: true, finalScore: 13),
    Score(isComplete: false, finalScore: 2),
    Score(isComplete: false, finalScore: 2),
]

获取完整的文本只需进行筛选即可。
let completeScores = scores.filter { $0.isComplete }

当然,如果您只需要将最终得分作为数组输出,您可以使用map方法实现:
let finalCompleteScores = completeScores.map { $0.finalScore }

这是您应该考虑数据的方式,而不是一堆需要保持同步的数组。

1
如果您可以将数据放入单个结构中,则这肯定是最佳解决方案,通常会导致更清洁、更易于维护的代码。如果由于其他设计原因必须有两个数组,则其他解决方案可能效果更好。 - user887210
我喜欢这个解决方案,因为我还可以添加得分的日期。然后我可以将日期/得分用于图表。我稍后会尝试它。 - SashaZ

1

同意并行数组方法不是最好的代码结构,但Eric使用的替代方案是reduce过滤和映射:

let completeHbiScores = zip(hbiCompleteArray, hbiScoreArray).reduce([Int]()){
    (newArray,zippedArray) in
    if zippedArray.0 {
        return newArray + [zippedArray.1]
    }
    else {
        return newArray
    }}

0

另一种相当简单的方法是只迭代一次您的数组,如下所示:

let hbiCompleteArray = [true, true, true, true, false, true, true, false, false]
let hbiScoreArray = [12, 12, 12, 12, 3, 13, 13, 2, 2]
var completeHbiScores = [Int]()

for score in hbiScoreArray.enumerated() {
  // break out of the loop if we're at the end of hbiCompleteArray
  // assuming that no value means default to false
  guard score.offset < hbiCompleteArray.count else { break }

  // go to the next score if the current element is false
  guard hbiCompleteArray[score.offset] else { continue }

  completeHbiScores.append(score.element)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接