티스토리 뷰

Swift&IOS

flatMap, compactMap

밀쿄 2020. 1. 10. 11:20

안녕하세요. 밀쿄 입니다.

오늘은 flatMap, compactMap에 대해서 알아보겠습니다.

flatMap에 쓰임새에 대해서 한 번 보겠습니다.

let language = [["C", "C++"], ["Objective-C", "Swift"], ["Java", "Kotlin"]]
print(language.flatMap({ $0 }))
//결과
//["C", "C++", "Objective-C", "Swift", "Java", "Kotlin"]

Sequence에서 각 요소들도 Sequence일 때 Elements를 flat하게 만들어줄 때 쓰곤했었죠.

스위프트 오픈 소스를 보면 다음과 같이 구현되어있습니다.

extension Sequence {
    public func flatMap<SegmentOfResult: Sequence>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] {
      var result: [SegmentOfResult.Element] = []
      for element in self {
        result.append(contentsOf: try transform(element))
      }
      return result
    }
}

내부에서 for문을 돌려서 배열에 append해서 그 결과값을 리턴해줍니다.

참고로 try이므로 에러를 던지는데 인자로 받은 함수가 에러를 던지므로 rethrows를 써준 것이 보입니다.

rethrows에 대한 정보는 여기를 참고 해주세요. 

정말 간단한 원리로 구현되는 것을 확인할 수 있습니다.

그리고 

flatMap은 위에서 보여준 구현말고 하나가 더 있습니다.

옵셔녈의 extension으로 존재합니다. 

public func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U? {
    switch self {
    case .some(let y):
        return try transform(y)
    case .none:
        return .none
    }
}

이런 구현을 가진 놈이 하나 있는데..

이걸 쓰면 다음과 같은 코드를 작성할 수 있습니다.

let number: Int? = Int("5968")
print(number.flatMap{$0 > 3000 ? $0: nil})
//출력
//Optional(5968)

여기서 만약에 map을 써도 될 것 같은데라고 생각이 들 수도 있어요.

근데 map을 쓰면

print(number.map{$0 > 3000 ? $0: nil} )
//출력
//Optional(Optional(5968))

이렇게 됩니다.

 

그 다음에는 compactMap입니다.

compactMap은 사실 Swift가 4.1까진 flatMap이란 이름으로 사용되었습니다.

let array = ["1", "2", "3", "F" ]
print(array.compactMap({ Int($0) }))
//출력
//[1,2,3]

이렇게 나옵니다. flatMap과 똑같은데 nil을 필터링 해주는 기능이 추가되어있다. 그런 느낌으로 이해하시면 됩니다.

이 녀석도 내부구현을 까보면..

extension Sequence {
      public func compactMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult] {
        return try _compactMap(transform)
      }

      public func _compactMap<ElementOfResult>( _ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult] {
        var result: [ElementOfResult] = []
        for element in self {
          if let newElement = try transform(element) {
            result.append(newElement)
          }
        }
        return result
      }
}

보이시나요 내부에서 Unwrapping해서 append해주는거?

그렇습니다. flatMapr과 compactMap은 사실 생각보다 더 간단한 원리로 돌아가고 있었습니다.

오늘은 여기서 끝입니다.

 

https://github.com/apple/swift/blob/da61cc8cdf7aa2bfb3ab03200c52c4d371dc6751/stdlib/public/core/SequenceAlgorithms.swift

 

apple/swift

The Swift Programming Language. Contribute to apple/swift development by creating an account on GitHub.

github.com

https://github.com/apple/swift/blob/da61cc8cdf7aa2bfb3ab03200c52c4d371dc6751/stdlib/public/core/Optional.swift

 

apple/swift

The Swift Programming Language. Contribute to apple/swift development by creating an account on GitHub.

github.com

 

'Swift&IOS' 카테고리의 다른 글

[MVC to MVVM 01] 일단 MVC부터..  (0) 2020.04.09
UIWindow  (1) 2020.01.13
rethrows  (0) 2020.01.09
StackView + ScrollView  (0) 2020.01.02
translatesAutoresizingMaskIntoConstraints  (0) 2019.12.30
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함