210423 Fri


  • SWIFTは、関数を1次オブジェクト
  • と見なす.
    →関数を他の関数の伝達因子として使用できる
  • パラメータを関数とする関数を高次関数
  • と呼ぶ.
  • 古典高次関数:マッピング、フィルタリング、ジッタなど
  • 出典:Sweet Programming(3版)第3部15章by Yagom

    1.最初の学習内容:マッピング(Map)

  • Mapは、自身を呼び出したときにパラメータとして渡される関数を実行し、結果
  • を返す関数です.
  • SWIFTでは、マップはタイル、ディックシャナ、スーツ、スタンドなどに使用できます.
  • マッピングを使用して、パラメータによって受信関数に各コンテナの値を適用し、コンテナにパッケージして
  • に戻ります.
  • 既存のコンテナの値は変更されず、新しいコンテナ
  • が作成され、戻されます.
    →従ってマッピングは常に既存データの変換(変換)に用いられる
    Q.なぜ地図を書くのですか?
  • コードの再利用とコンパイラ最適化の観点から、for in構文と性能の違いがあります.
  • マルチスレッド環境では、ターゲットコンテナの値がスレッドで変更すると、異なるスレッドで同時に値の変更を試みるときに予知できない副作用
  • が発生することを防止することができる.
    構文
    import Foundation
    
    let numbers: [Int] = [0, 1, 2, 3, 4]
    
    var doubledNumbers: [Int] = [Int]()
    var strings: [String] = [String]()
    
    for number in numbers {
        doubledNumbers.append(number * 2)
        strings.append("\(number)")
    }
    
    print(doubledNumbers) // [0, 2, 4, 6, 8]
    print(strings) // ["0", "1", "2", "3", "4"]
    mapメソッドの使用
    import Foundation
    
    let numbers: [Int] = [0, 1, 2, 3, 4]
    
    var doubledNumbers: [Int] = [Int]()
    var strings: [String] = [String]()
    
    doubledNumbers = numbers.map({ (number: Int) -> Int in
        return number * 2
    })
    
    strings = numbers.map({ (number: Int) -> String in
        return "\(number)"
    })
    
    print(doubledNumbers) // [0, 2, 4, 6, 8]
    print(strings) // ["0", "1", "2", "3", "4"]
    モジュール表示の簡略化
    import Foundation
    
    let numbers: [Int] = [0, 1, 2, 3, 4]
    
    // 기본 클로저 표현식 사용
    var doubledNumbers = numbers.map({ (number: Int) -> Int in
        return number * 2
    })
    
    // 매개변수 및 반환 타입 생략
    doubledNumbers = numbers.map({ return $0 * 2 })
    print(doubledNumbers) // [0, 2, 4, 6, 8]
    
    // 반환 키워드 생략
    doubledNumbers = numbers.map({ $0 * 2 })
    print(doubledNumbers) // [0, 2, 4, 6, 8]
    
    // 후행 클로저 사용
    doubledNumbers = numbers.map{ $0 * 2 }
    print(doubledNumbers) // [0, 2, 4, 6, 8]
    エンクロージャの再利用
    import Foundation
    
    let evenNumbers: [Int] = [0, 2, 4, 6, 8]
    let oddNumbers: [Int] = [0, 1, 3, 5, 7]
    let multiplyTwo: (Int) -> Int = { $0 * 2 }
    
    let doubledEvenNumbers = evenNumbers.map(multiplyTwo)
    print(doubledEvenNumbers) // [0, 4, 8, 12, 16]
    
    let doubledOddNumbers = oddNumbers.map(multiplyTwo)
    print(doubledOddNumbers) // [0, 2, 6, 10, 14]

    2.2番目の学習内容:フィルタ(Filter)


  • フィルタは、名前の通り、容器内の値をフィルタして抽出する高次関数です.

  • 地図と同様に、新しいコンテナに値を含めて返します.

  • 異なる点は、マッピングのように変形するのではなく、特定の条件に基づいて既存のコンテンツをフィルタリングできることです.

  • filter関数のパラメータとして渡される関数の戻りタイプはBool

  • コンテンツの値があり、アイテムが新しいコンテナに含まれると判断した場合はtrueを返し、含まない場合はfalseを返します.
  • フィルタ方法の使用
    import Foundation
    
    let numbers: [Int] = [0, 1, 2, 3, 4, 5]
    
    let evenNumbers: [Int] = numbers.filter { (number: Int) -> Bool in
        return number % 2 == 0
    }
    print(evenNumbers) // [0, 2, 4]
    
    let oddNumbers: [Int] = numbers.filter{ $0 % 2 == 1 }
    print(oddNumbers) // [1, 3, 5]
    マッピングとフィルタリング方法の関連付けの使用
    import Foundation
    
    let numbers: [Int] = [0, 1, 2, 3, 4, 5]
    
    let mappedNumbers: [Int] = numbers.map{ $0 + 3 }
    
    let evenNumbers: [Int] = mappedNumbers.filter { (number: Int) -> Bool in
        return number % 2 == 0
    }
    print(evenNumbers) // [4, 6, 8]
    
    // mappedNumbers를 굳이 여러 번 사용할 필요가 없다면 메서드를 체인처럼 연결하여 사용할 수 있음
    let oddNumbers: [Int] = numbers.map{ $0 + 3 }.filter{ $0 % 2 == 1 }
    print(oddNumbers) // [3, 5, 7]

    3.3つ目の学習内容:Reduce

  • Reduce機能は「連結」(Combine)と呼ぶべきである.
  • リスナーは、コンテナ内のコンテンツを統合する高度な関数
  • を実行する.
  • アレイの場合、アレイ内のすべての値は、入力パラメータによって伝達されるモジュールの演算結果に統合されます.
    SwiftのReduceには2つの形式があります
    最初のreduceは、各要素を受信して演算し、次のモジュールを実行するために値を返す循環コンテナです.
    public func reduce<Result>(_ initialResult: Result,
    	 _nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
    第2の再生方法は、コンテナを循環させ、キャビネットを実行しますが、キャビネットは結果値を返しません.inoutパラメータを使用して初期値を直接演算します
    public func reduce<Result>(into initialResult: Result,
    		_ updateAccumulatingResult: (inout Result, Element) throws -> ()) rethrows -> 
    		Result
    reduceメソッドの使用
    初期値は0で、整数配列のすべての値を追加します.
    import Foundation
    
    let numbers: [Int] = [1, 2, 3]
    
    // 첫 번째 형태인 reduce(_:_:) 메서드의 사용
    
    var sum: Int = numbers.reduce(0, { (result: Int, next: Int) -> Int in
        print("\(result) + \(next)")
    //    0 + 1
    //    1 + 2
    //    3 + 3
        return result + next
    })
    
    print(sum) // 6
    初期値は0で、整数配列のすべての値を減算します.
    let subtract: Int = numbers.reduce(0, { (result: Int, next: Int) -> Int in
        print("\(result) - \(next)")
    //    0 - 1
    //    -1 - 2
    //    -3 - 3
        return result - next
    })
    
    print(subtract) // -6
    初期値は3で、整数配列のすべての値を加算します.
    let sumFromThree: Int = numbers.reduce(3) {
        print("\($0) + \($1)")
    //    3 + 1
    //    4 + 2
    //    6 + 3
        return $0 + $1
    }
    
    print(sumFromThree) // 9
    初期値は3で、整数配列のすべての値を減算します.
    var subtractFromThree: Int = numbers.reduce(3) {
        print("\($0) - \($1)")
    //    3 - 1
    //    2 - 2
    //    0 - 3
        return $0 - $1
    }
    
     print(subtractFromThree) // -3
    reduce(:)メソッドを使用して文字列配列を接続する
    import Foundation
    
    let names: [String] = ["Sunny", "Steven", "Summer", "Kio", "Tak", "Coda"]
    
    let reducedNames: String = names.reduce("yagom 2기 캠퍼들 : ") {
        return $0 + ", " + $1
    }
    
    print(reducedNames) // yagom 2기 캠퍼들 : , Sunny, Steven, Summer, Kio, Tak, Coda
    reduce(int::)メソッドを使用する第2の形式
    初期値は0で、整数配列のすべての値を加算します.
    最初のタイルとは異なり、エンクロージャの値は返されません.
    異なる点は、以前の値を直接内部で変更することです.
    import Foundation
    
    let numbers: [Int] = [1, 2, 3]
    
    var sum = numbers.reduce(into: 0, { (result: inout Int, next: Int) in
        print("\(result) + \(next)")
    //    0 + 1
    //    1 + 2
    //    3 + 3
        result += next
    })
    
    print(sum) // 6
    初期値は3で、整数配列のすべての値を減算します.
    最初のタイルとは異なり、エンクロージャの値は返されません.
    異なる点は、以前の値を直接内部で変更することです.
    var subtractFromThree = numbers.reduce(into: 3, {
        print("\($0) - \($1)")
    //    3 - 1
    //    2 - 2
    //    0 - 3
        $0 -= $1
    })
    
    print(subtractFromThree) // -3
    最初のタイル形状とは異なるため、異なるコンテナ値を変更して配置することもできます.
    これにより、マップやフィルタのような形状を使用できます.
    奇数をフィルタリングし、偶数を元の2倍に変更することで、[1,2,3]配列を直接演算できます.

    警備員のドアの下.isは何ですか.
    間違いがあったが、ロビーは...🤔
    フィルタとマップの外観の使用
    var doubledNumbers = [1, 2] + numbers.filter{ $0.isMultiple(of: 2) }.map { $0 * 2 }
    print(doubledNumbers) // [1, 2, 4]
    すべての名前を大文字に変換し、初期値が空の配列に直接演算します.
    let names: [String] = ["Sunny", "Steven", "Summer", "Kio", "Tak", "Coda"]
    
    var upperCasedNames: [String]
    upperCasedNames = names.reduce(into: [], {
        $0.append($1.uppercased())
    })
    
    print(upperCasedNames) // ["SUNNY", "STEVEN", "SUMMER", "KIO", "TAK", "CODA"]
    マップの外観を使用する
    var upperCasedNames = names.map { $0.uppercased() }
    print(upperCasedNames) // ["SUNNY", "STEVEN", "SUMMER", "KIO", "TAK", "CODA"]
    マップ、フィルタ、およびリフレッシュ方法の関連付けの使用
    let numbers: [Int] = [1, 2, 3, 4, 5, 6, 7]
    
    // 짝수를 걸러내어 각 값에 3을 곱해준 후 모든 값을 더함
    
    var result: Int = numbers.filter{ $0.isMultiple(of: 2) }.map{ $0 * 3 }.reduce(0){ 
    $0 + $1 }
    print(result) // 36
    for in構文を使用する場合
    let numbers: [Int] = [1, 2, 3, 4, 5, 6, 7]
    var result = 0
    
    for number in numbers {
        guard number.isMultiple(of: 2) else {
            continue
        }
        
        result += number * 3
    }
    
    print(result) // 36

    マップ、フィルタ、タイルの使用

    import Foundation
    
    enum CoffeeType {
        case caffeine, decaffeination, unknown
    }
    
    struct coffeeMenu {
        let name: String
        let coffeeType: CoffeeType
        var price: UInt
    }
    
    var coffees: [coffeeMenu] = [coffeeMenu]()
    
    coffees.append(coffeeMenu(name: "카페 라떼", coffeeType: .caffeine, price: 4000))
    coffees.append(coffeeMenu(name: "따듯한 아메리카노", coffeeType: .caffeine, price: 3500))
    coffees.append(coffeeMenu(name: "에티오피아 원두 커피", coffeeType: .decaffeination, price: 3500))
    
    // 카페인이 들어가면서 가격이 4천원 이하인 커피 메뉴 찾기
    
    var result: [coffeeMenu] = coffees.map{ coffeeMenu(name: $0.name, coffeeType: $0.coffeeType, price: $0.price) }
    
    result = result.filter{ $0.coffeeType == .caffeine && $0.price <= 4000 }
    
    let string: String = result.reduce("카페인이 들어가면서 가격이 4천원 이하인 커피 메뉴 ☕️") { $0 + "\n" + "\($1.name) \($1.coffeeType) \($1.price)원"}
    
    print(string)
    //카페인이 들어가면서 가격이 4천원 이하인 커피 메뉴 ☕️
    //카페 라떼 caffeine 4000원
    //따듯한 아메리카노 caffeine 3500원