Menu
Coddy logo textTech

カスタム高階関数

CoddyのSwiftジャーニー「ロジックとフロー」セクションの一部 — レッスン 42/56。

これで、独自の高階関数を作成できるようになり、それらは mapfilter と並んで違和感なく馴染むでしょう。その形式は常に同じです。クロージャのパラメータを受け取り、ループ内でそれを呼び出し、結果を返します。

extension Array {
    func myMap<T>(_ transform: (Element) -> T) -> [T] {
        var result: [T] = []
        for item in self {
            result.append(transform(item))
        }
        return result
    }
}

[1, 2, 3].myMap { $0 * 10 }       // [10, 20, 30]

エクステンションが大げさに感じられる場合は、代わりにフリー関数を記述してください。考え方は同じです:

func count<T>(_ items: [T], where predicate: (T) -> Bool) -> Int {
    var n = 0
    for item in items where predicate(item) {
        n += 1
    }
    return n
}

クロージャを自由に受け渡せるようになると、標準ライブラリは魔法のようなものではなく、自分でも書けるようなパターンの集まりに見えてくるはずです。

challenge icon

チャレンジ

中級

配列を一度だけ走査し、述語(predicate)を満たす要素とそれ以外の要素を、それぞれ元の順序を維持したタプル (matched, rest) として返すフリー関数 partition(_ items: [Int], by predicate: (Int) -> Bool) -> ([Int], [Int]) を作成してください。

2行の入力を読み取ります。1行目は整数 min、2行目はカンマ区切りの整数のリストです。作成した partition 関数を使用し、n > min かどうかをチェックする述語を渡してください。以下の形式で出力します:

  1. matched: <...>
  2. rest: <...>

各リストは , で結合してください(出力する要素がない場合は空にします)。

入力が 5 / 2,7,3,8,5 の場合、出力は以下のようになります:

matched: 7,8
rest: 2,3,5

チートシート

高階関数は一貫したパターンに従います。クロージャを受け取り、ループ内でそれを呼び出し、結果を返します。

エクステンションとして:

extension Array {
    func myMap<T>(_ transform: (Element) -> T) -> [T] {
        var result: [T] = []
        for item in self {
            result.append(transform(item))
        }
        return result
    }
}
[1, 2, 3].myMap { $0 * 10 }  // [10, 20, 30]

フリー関数として:

func count<T>(_ items: [T], where predicate: (T) -> Bool) -> Int {
    var n = 0
    for item in items where predicate(item) {
        n += 1
    }
    return n
}

一致した要素と一致しなかった要素のタプルを返す partition 関数:

func partition(_ items: [Int], by predicate: (Int) -> Bool) -> ([Int], [Int]) {
    var matched: [Int] = []
    var rest: [Int] = []
    for item in items {
        if predicate(item) { matched.append(item) }
        else { rest.append(item) }
    }
    return (matched, rest)
}

自分で試してみよう

let min = Int(readLine()!)!
let nums = readLine()!.components(separatedBy: ",").map { Int($0)! }

// TODO: partition(_:by:) -> ([Int], [Int]); 条件に一致するものとそれ以外を分けて出力する
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

ロジックとフローのすべてのレッスン