Notice
Recent Posts
Recent Comments
Link
관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 2. Higher order function (고차함수) 직접 구현 방법 - flatMap, compactMap 본문

iOS 응용 (swift)

[iOS - swift] 2. Higher order function (고차함수) 직접 구현 방법 - flatMap, compactMap

jake-kim 2022. 12. 1. 22:29

1. Higher order function (고차함수) 직접 구현 방법 - map, filter, reduce

2. Higher order function (고차함수) 직접 구현 방법 - flatMap, compactMap

flatMap, compactMap

  • flatMap, compactMap은 higher order function (고차함수)
  • higher order function이란? 다음 두 가지 중 하나에 해당
    • 하나 이상의 함수를 인자로 받는 것
    • 함수를 결과로 리턴하는것

flatMap

  • 옵셔널바인딩 + nil제거 + 차원 축소
  • swift4.1부터는 flatMap을 사용할땐 차원 축소 기능만 사용하려고하고, 옵셔널 바인딩과 nil제거는 compcatMap을 사용 권장
[[1,2], [3,4]].flatMap { $0 } // [1,2,3,4]
[1,2,nil,3,4,Optional(5)].flatMap { $0 } // [1,2,3,4]
  • 구현 방법
    • 핵심 - 반환값이 축소가 차원되어야 하므로, Sequence형태인 제네릭 T를 선언하고 [T.Element]를 리턴 하도록 하면 차원축소가 가능
    • 파라미터 함수는 Optional 반환이 가능하게하고, 내부적으로 optional binding하여 처리
extension Array {
  func myFlatMap<T: Sequence>(_ f: (Element) -> T?) -> [T.Element] {
    var ret = [T.Element]()
    for x in self {
      if let element = f(x) {
        ret.append(contentsOf: element)
      }
    }
    return ret
  }
}

[[1,2], [3,4]].myFlatMap { $0 } // [1, 2, 3, 4]
  • 차원을 축소시키지 않고 단순히 optinoal binding, nil 제거 역할만 하는 flatMap 함수는 별도로 정의
extension Array {  
  func myFlatMap2<T>(_ f: (Element) -> T?) -> [T] {
    var ret = [T]()
    for x in self {
      if let element = f(x) {
        ret.append(element)
      }
    }
    return ret
  }
}

// [1,2,nil,3,4,Optional(5)].myFlatMap2 { $0 } // [1, 2, 3, 4, 5]

CompactMap

  • 옵셔널바인딩 + nil제거
  • 구현 방법
    • 기존에 있는 Element 제네렉 하나만 쓰면 될것 같지만, 외부에서 주입해주는 함수는 Optional 타입반환이 가능하게 해야하고, 최종적으로는 non-optional 배열을 반환하기 위해서 T를 새로 선언
extension Array {
  func myCompactMap<T>(_ f: (Element) -> T?) -> [T] {
    var ret = [T]()
    for x in self {
      if let element = f(x) {
        ret.append(element)
      }
    }
    return ret
  }
}

// [1,2,nil,3,4,Optional(5)].myCompactMap { $0 } // [1, 2, 3, 4, 5]
  • 만약 Element로만 한다면, 모두 옵셔널을 반환되므로 주의
    •  Element에 ?를 붙이게 되면 암묵적으로 최종 리턴 타입에서도 Element가 Optional 타입이 될 수 있다고 제네릭이 해석
extension Array {
  func myCompactMap2(_ f: (Element) -> Element?) -> [Element] {
    var ret = [Element]()
    for x in self {
      if let element = f(x) {
        ret.append(element)
      }
    }
    return ret
  }
}

[1,2,nil,3,4,Optional(5)].myCompactMap2 { $0 } 
// [Optional(1), Optional(2), Optional(3), Optional(4), Optional(5)]
Comments