티스토리 뷰

Swift

Swift4.1 ) flatMap -> compactMap

Zedd0202 2018. 3. 11. 11:42
반응형

안녕하세요 :) Zedd입니다.

평소처럼 블로그를 보고 있던 중...여기에서 (저만) 놀라운 사실을 발견했어요 :)


flatMap -> compactMap



네. 그렇습니다. Swift 4.1에서 flatMap이 compactMap이라는 이름으로 바뀝니다!!!!

하지만!!!!!!!!!!!!!!!!!!!!! flatMap이 사라지는건 아닙니다. 

부분적으로 정말 딱 그 순간에만 


이미지출처 : https://useyourloaf.com/blog/replacing-flatmap-with-compactmap/


ㅠ(지금 이 상황에서) flatMap은 deprecate됐어.....compactMap을 써줄래.....?라고 나오게 됩니다.

이미...



여기엔 (벌써)Deprecated된다고 나옴..

그러나!!!!!!!!


여기는 deprecate내용이 없네요 :)

또 다른 쓰임이 있는데, 그러니까!!!!!!!!!!!!!!!!!!!! 쓰임에 따라서 그걸 compactMap을 써야할지 flatMap을 써야할지 구별해야한다는 것입니다.

Declaration을 봐도 조금 다르죠??


어떤 상황에서 compactMap으로 바뀌는지 조금 더 알아봅시다.

배열(Array)와 같이 sequence에 flatMap을 사용하여 nil에 매핑되는 모든것을 필터링하던 그!!! 작업?

let possibleNumbers = ["1", "2", "three", "///4///", "5"]

let mapped: [Int?] = possibleNumbers.map { str in Int(str) }
// [1, 2, nil, nil, 5]

let flatMapped: [Int] = possibleNumbers.flatMap { str in Int(str) }
// [1, 2, 5]


바로 이러한 상황이죠. 이러한 상황에서의 flatMap은  Swift 4.1에서는 더이상 사용되지 않으며, compactMap으로 대체됩니다.

정의를 잠깐보면..


func flatMap<U>(_ transform: (Self.Element) throws -> U?) rethrows -> [U]


딱 이런케이스에서


let names: [String?] = ["Tom"nil"Peter"nil"Harry"]

let counts = names.compactMap { $0?.count }

// [3, 5, 5]


이제 compactMap이 사용됩니다. 

하지만, 바로 위와같은 케이스 단 하나에서만 compactMap을 사용해야 하는 것이며, 다른 상황?, 케이스에 대해서는 여전히 flatMap을 사용해야합니다.



1. 각 요소요소가 sequence일 때 flat하게 만들어주는 flatMap이 있었죠!

let scores = [[5,2,7], [4,8], [9,1,3]]
let allScores = scores.flatMap { $0 }
// [5, 2, 7, 4, 8, 9, 1, 3]

let passMarks = scores.flatMap { $0.filter { $0 > 5} }
// [7, 8, 9]

바로 이런 케이스에서요!

이럴땐 여전히 flatMap이 사용되게 됩니다. 



2. Optional에서의 flatMap사용

func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?


let input: Int? = Int("8")

let passMark: Int? = input.flatMap { $0 > 5 ? $0 : nil}

// Optional(8)


아주 지극히 개인적인 생각.....이지만.. 솔직히 flatMap하면


let names: [Int?] = [1, nil, 3, nil, 5]

let valid = names.flatMap { $0 }

print(valid)//[1, 3, 5]


저는 이런느낌이 조금 더 강하거든요. nil이 있으면 알아서 걸러주고...이런거(위 케이스는 이제 compactMap으로 바뀌겠지만요)


let input: Int? = Int("8")

let passMark: Int? = input.flatMap { $0 > 5 ? $0 : nil}

// Optional(8)


근데 flatMap에서 Optional이 나온다는게 저는 처음에 음? flatMap은 값이 있으면 그 값을 뽑아주고 뭐 그런거 아니었어? 라고 해서 조금 헷갈렸어요 :)......

위 케이스에서 Optional(8)이 나온이유는 애초에 여기서의 flatMap의 정의가

func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?

이것이기 때문입니다.

자. input으로 Int? 즉 Optional값을 받았어요. 그리고 그 input으로 flatMap을 호출하네요. 바로 Optional에서의 

flatMap을 호출하게 될 것입니다. 

let passMark: Int? = input.flatMap { $0 > 5 ? $0 : nil}


여기서 리턴타입이 Int?죠? Optional이죠? 


func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?

그럼여기서 U? ==  Int?일것이고, 최종적으로 U == Int일거에요. 

그렇다면 최종적으로 Optional에서의 flatMap은 U?를 반환하니까, U는 Int였으니까, Int?를 반환하게 될 거에요. 그래서!!!!!!! 결과가 Optional(8)이 나오게 되었답니다 :)

아무튼...이 Optional의 케이스에서도 여전히 flatMap이 사용되게 될거에요.


여기에서는 이렇게 flatMap이 compactMap으로 바뀐 이유가, map으로도 할 수 있는 작업에서 flatMap을 오용하는 상황을 방지하려고 바뀌는 것 같다고 해요 :)



그러니까 지금 조금 혼란이 오실 수도 있는데!!!!!!!!정리하자면!!!!!!!

Swift에서는 flatMap의 정의가 이렇게 3가지 있었는데!!!!


Sequence.flatMap<S>(_: (Element) -> S) -> [S.Element]
    where S : Sequence
Optional.flatMap<U>(_: (Wrapped) -> U?) -> U?
Sequence.flatMap<U>(_: (Element) -> U?) -> [U]


여기서 마지막거인 


Sequence.flatMap<S>(_: (Element) -> S) -> [S.Element]
    where S : Sequence
Optional.flatMap<U>(_: (Wrapped) -> U?) -> U?
Sequence.flatMap<U>(_: (Element) -> U?) -> [U]


이것만 이제 compactMap으로 바뀐다...라는 것만 아시면 됩니다.

자세한 변경사항?..은 Apple Swift evolution을 참고해주세요 :)

XD


+) 여담이지만



도큐먼트에서 이런거 있었나요?!!?...저는 어제 처음봤어요..!!!! 뭐가 수정됐고, 뭐가 추가됐고 이런걸 한눈에 볼 수 있더라구요!!!



Xcode 9.2-9.3 beta 4에서는 BusinessChat이 추가가 되고, 여러개가 바뀌었구나~~라는것을 한눈에 볼 수 있죠



계속 타고타고 들어가도 이렇게 한눈에 보여줍니다. CoreAnimation이 바뀌었다는데..어떤게 바뀐거지? 하고 들어가면 또 여기서 뭐가 바뀐건지 표시를 해줘요 :)

갸앙 

오늘도 도움이 되었길 바랍니다 :)


참고 : https://github.com/apple/swift-evolution/blob/master/proposals/0187-introduce-filtermap.md

https://useyourloaf.com/blog/replacing-flatmap-with-compactmap/


반응형