†でおきしブログ†

ウナギ食べたいヽ(•̀ω•́ )ゝ✧

【Swift3.0】配列中の文字列をIntに型変換するreduce処理に頭を悩ますなど

☆これ

let arr = ["a","1","b","2"].reduce([]){$0 + (Int($1).map{[$0]} ?? [] )}
print(arr) //[1, 2]

QiitaのSwift記事でこういう処理に遭遇したのですが、なんでそうなるのか理解できなくて半日ほど悩んだのでメモ。
要は文字と数字を含む文字列配列 ["a","1","b","2"] から数字だけ抽出して [1, 2] に変換するっていう処理。

★元にした記事はコチラ

qiita.com
koherさんのコメントにある処理です。

☆とりあえず現状の理解

  • reduceの初期値を空配列とします([])
  • ショートハンド引数が $0,$1,$0 の順番で出現しています
    • 最初の$0,$1はreduceのtotal,valueに相当する
    • 最後の$0はmapの引数
  • 型変換をしているInt($1)の戻り値はOptional型で返却される
    • 従ってmapはOptionalのメソッドとなる(要素がひとつの配列のmapと同様の振る舞い)
    • map処理で[$0]と括弧で囲んでいるのは配列要素として返却するため
  • "??"によってnilの場合には空配列要素を設定("a"などの文字の場合にnilとなる)
    • !(アンラップ)やif,guardを用いたOptional Bindingと同様に、非オプショナル型を扱う処理を行っています
  • 結果、$0(total) + $1(value)[数値のみの配列要素] とする事で、数値配列を生成しています

☆ショートハンドを使わずにreduceの処理を書いてみた

let arr2 = ["a","1","b","2"].reduce([]){ (total,value)->Array<Int> in 
    guard var chk = Int(value) else{
        //Optional Binding
        return total
    }
    return total + [chk]
}
print(arr2) //[1, 2]

mapと"??"を使わず、素直にguardを使って処理を書いてます。
Array返却なので戻り値の型はArrayとしています。

一見簡単そうに見えたSwiftですが、なかなか難しそう…(勉強中)

☆蛇足

SwiftはWeb上のsandboxでカジュアルに動作を確認する事ができます。
冒頭のコードを張り付けて実行すると[1,2]が出力されます。

IBM Swift Sandbox