Swift фильтрует другие массивы на основе другого массива Bool


У меня есть массив Bools, и я хочу отредактировать массив оценок и массив дат для значений, которые являются ложными. Я не могу до него добраться. Я думал о том, чтобы получить элементы, которые являются ложными, и использовать этот массив, чтобы удалить эти элементы из массива баллов, но я могу представить, что есть прямой способ сделать это.

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]

4 4

4 ответа:

Если вы должны использовать два массива, вы можете решить это с помощью zip, filter и map Вот так:

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.

[4] здесь очень важен комментарий вадиана. Вы не должны иметь несколько массивов таким образом. Создайте структуру, содержащую данные:

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 }

Вот как вы должны думать. о ваших данных, а не как куча массивов, которые вы должны синхронизировать.

Согласитесь, что подход параллельных массивов не является лучшей структурой для использования в коде, но альтернативой фильтрам и картам, используемым Eric, является reduce:

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

Еще один довольно простой способ сделать это, который повторяется только один раз через ваши массивы:

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