🌾

[Swift] [Combine] removeDuplicates で nil を含む場合の compactMap の位置について

2021/12/26に公開

はじめに

removeDuplicatesnil を含む配列を扱うときの compactMap の位置による挙動の違いというかなりマニアックな記事になります。

removeDuplicates の基本的な挙動

removeDuplicates の基本的な挙動は以下の通りです。

import Combine

let nums: [Int] = [0, 0, 0, 0, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 0]

let cancellable = nums.publisher
    .removeDuplicates()
    .sink {
        print("\($0)") // 0 1 2 3 4 0
    }

一つ前と連続してきた出力がきた場合に、その出力をなかったことにします。

compactMap の位置による挙動の違い

compactMap の位置による挙動の違いは以下の通り。

import Combine

let nums: [Int?] = [0, nil, 0, nil, nil, 1, 2]

// removeDuplicates より先に compactMap する
let cancellableA = nums.publisher
    .compactMap { $0 } // [0, 0, 1, 2]
    .removeDuplicates() // [0, 1, 2]
    .sink {
        print("\($0)") // 0 1 2
    }

// removeDuplicates の後に compactMap する
let cancellableB = nums.publisher
    .removeDuplicates() // [0, nil, 0, nil, 1, 2]
    .compactMap { $0 } // [0, 0, 1, 2] 
    .sink {
        print("\($0)") // 0 0 1 2
    }

どちらが良いということではないですが、知っておかないと意図しない挙動が起こりかねないので、compactMap の位置には気をつけてましょう(戒め)

GitHubで編集を提案

Discussion