🕊

[Swift] 配列をペアに変換して処理する方法

2021/12/25に公開約3,300字

はじめに

配列を処理するときに次の要素を扱う方法の記事を参考にいろいろとアレンジしてみました。
また、空配列がやってきたりして、ペアの生成に失敗したときにエラーにならないことも確認しながら書いてみました。

パターン1:最後の要素のペアにはnilを入れたい場合

extension Array {
    var pair: [(Element, Element?)] {
        var copy: [Element?] = self
        copy.append(nil)
        return enumerated().map { ($0.element, copy[$0.offset + 1]) }
    }
}

let nums = [1,2,3]
nums.pair.forEach { num1, num2 in
    guard let num2 = num2 else {
        return
    }
    print("\(num1) * \(num2) = \(num1 * (num2))")
}
//  出力
//  1 * 2 = 2
//  2 * 3 = 6

let empty: [Int]  = []
empty.pair.forEach { num1, num2 in
    guard let num2 = num2 else {
        return
    }
    print("\(num1) * \(num2) = \(num1 * (num2))")
}
//  出力
//  なし

パターン2:最後の要素のペアには先頭の要素とペアにしたい場合

extension Array {
    var pair: [(Element, Element)]? {
        var copy: [Element] = self
        guard let first = self.first else { // このguard文で早期リターンさせないと空の配列が来たときに実行時エラーになる
            return nil // 空配列を返却してもよいがpairが作れなかったという意味も込めてnilを返す
        }
        copy.append(first)
        return enumerated().map { ($0.element, copy[$0.offset + 1]) }
    }
}

let nums = [1,2,3]
nums.pair?.forEach { num1, num2 in
    print("\(num1) * \(num2) = \(num1 * (num2))")
}
// 出力
// 1 * 2 = 2
// 2 * 3 = 6
// 3 * 1 = 3 ← 最後のペアには先頭の要素が入る

let empty: [Int]  = []
empty.pair?.forEach { num1, num2 in
    print("\(num1) * \(num2) = \(num1 * (num2))")
}
// 出力
// なし

パターン3:最後の要素のペアを自由に変更させたい場合

extension Array {
    func pair(lastPairIndex: Int? = 0) -> [(Element, Element?)] {
        var copy: [Element?] = self
        var lastPair: Element?
        if let lastPairIndex = lastPairIndex, self.indices.contains(lastPairIndex) {
            lastPair = self[lastPairIndex]
        } else {
            lastPair = nil
        }
        copy.append(lastPair)
        return enumerated().map { ($0.element, copy[$0.offset + 1]) }
    }
}

let nums = [1,2,3]
nums.pair(lastPairIndex: nil).forEach { num1, num2 in
    guard let num2 = num2 else {
        return
    }
    print("\(num1) * \(num2) = \(num1 * (num2))")
}
// 出力
// 1 * 2 = 2
// 2 * 3 = 6

nums.pair().forEach { num1, num2 in
    guard let num2 = num2 else {
        return
    }
    print("\(num1) * \(num2) = \(num1 * (num2))")
}
// 出力
// 1 * 2 = 2
// 2 * 3 = 6
// 3 * 1 = 3

// こういうこと(最後は最後の値とペアになる)も可能
nums.pair(lastPairIndex: nums.indices.last).forEach { num1, num2 in
    guard let num2 = num2 else {
        return
    }
    print("\(num1) * \(num2) = \(num1 * (num2))")
}
// 出力
// 1 * 2 = 2
// 2 * 3 = 6
// 3 * 3 = 9 ← 最後は最後の値とペアになる


let empty: [Int]  = []
empty.pair().forEach { num1, num2 in
    guard let num2 = num2 else {
        return
    }
    print("\(num1) * \(num2) = \(num1 * (num2))")
}
// 出力
// なし

empty.pair(lastPairIndex: nil).forEach { num1, num2 in
    guard let num2 = num2 else {
        return
    }
    print("\(num1) * \(num2) = \(num1 * (num2))")
}
// 出力
// なし

// こいうことしてもエラーにはならない
empty.pair(lastPairIndex: 100).forEach { num1, num2 in
    guard let num2 = num2 else {
        return
    }
    print("\(num1) * \(num2) = \(num1 * (num2))")
}
// 出力
// なし

さいごに

Array の Array[Index] でのアクセスは実行時まで、エラーに気づかないので self.indices.contains(Index) で Index が存在することを確認してからアクセスした方がいいです。

というよりも、そのようなアクセスをする処理を書かないのがベターです。

GitHubで編集を提案

Discussion

ログインするとコメントできます