【问题标题】:Swift Filter other arrays based on another Bool arraySwift 根据另一个 Bool 数组过滤其他数组
【发布时间】:2017-02-07 19:53:32
【问题描述】:

我有一个布尔数组,想要编辑一个分数数组和一个日期数组,以获取 False 的值。我做不到。我想过获取错误的元素并使用该数组从分数数组中删除这些元素,但我可以想象有一种直接的方法。

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

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

我想要一组 completeHbiScores = [12, 12, 12, 12, 13, 13]

【问题讨论】:

标签: arrays swift filter flatmap


【解决方案1】:

如果您必须使用两个数组,您可以使用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 值。

【讨论】:

  • 如果数组不是太大,这是一种很好且相当简单的方法。唯一的问题是这些操作中的每一个都遍历数组,因此它可能会在大型数组上陷入困境。优化就够了吗?这由您决定,当然不要选择更复杂的解决方案,除非测试表明这对于您的需求来说太慢了。
  • @ColGraff 确实它会迭代多次,但是我认为这不是问题,甚至不是问题,在这里。我们可以猜测 OP 在他们的数组中不会有数十亿的分数——此外,Zip2Sequence 的性质(不是实际的数组)以及过滤器/映射被优化的事实(缓冲区、写时复制、编译器优化等) ) 让我说这里真的很好。 :)
  • 我同意这可能不是问题,并且在没有测试瓶颈的情况下切换到另一个解决方案绝对是过早的优化。使用此解决方案是因为它的简单性和清晰性,如果测试表明它是一个瓶颈,则对其进行优化。这应该是大多数软件开发的指南!
  • 请注意,您也可以使用flatMap 代替filtermap,例如let result = zip(hbiCompleteArray, hbiScoreArray).flatMap {$0 ? $1 : nil} :)
  • 效果很好,非常优雅。现在尝试使用相同的方法返回日期数组。谢谢
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    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 }
    

    当然,如果您只想将最终分数作为一个数组,您可以映射到该数组:

    let finalCompleteScores = completeScores.map { $0.finalScore }
    

    这就是你应该如何看待你的数据,而不是你必须保持同步的一堆数组。

    【讨论】:

    • 如果您可以将数据放入单个结构中,这无疑是最佳解决方案,它通常会导致代码更清晰且更易于维护。如果您出于其他设计原因必须有两个数组,那么其他解决方案可能会更好。
    • 我喜欢这个解决方案,因为我还可以添加乐谱的日期。然后我可以使用图表的日期/分数。我稍后会尝试。
    【解决方案4】:

    另一种相当简单的方法是:只在数组中迭代一次:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-30
      • 2014-05-03
      • 2022-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-02
      相关资源
      最近更新 更多