2015년 9월 1일 화요일

Swift - flatMap 넌 도대체 뭐냐?

Swift 2 에서 map 과 비슷한 flatMap 이라는 녀석을 사용 할 수 있다. 애초에 map 의 용도는 '배열의 각 아이템을 가공해서 다른 배열을 만드는 것'이다. 그렇다면 평평하다는 이름을 가진 flatMap 은 어떤 용도일까?

이 글에는 flatMap 이 무엇인지에 대한 명확한 해답이 없다. 그냥 특징만 나열해 놓고 '뭐에 쓰는 것임' 이라고 징징거리는 글이다. -_-;;

flatMap 의 특징을 보자.

옵셔널을 풀어버린다

옵셔널을 풀어버린다는 말은 다르게 말해서 옵셔널 nil 아이템을 없애버린다는 말과 동일하다. 일단 예제로 아래의 리스트를 보자.
let items: [Int?] = [1, 2, nil, 4, 5, nil, 7]
이 리스트를 map과 flatMap을 사용해 시험해 보자.

우선은 map 을 사용한 예제이다.
let mapItems = items.map { $0 }
mapItems
// [{Some 1}, {Some 2}, nil, {Some 4}, {Some 5}, nil, {Some 7}]
결과는 당연히 똑같은 리스트가 하나 더 튀어나온다. 당연하겠지만, 앞서 정의한 items 라는 배열은 Array<Int?> 타입이니 map 의 클로져에 전달되는 파라미터도 당연히 Int? 다.

하지만 flatMap은 좀 다른 식으로 동작한다.
let flatMapItems = items.flatMap { $0 }
flatMapItems
// [1, 2, 4, 5, 7]
결과를 보면 Some 이라는 표현이 없다. 즉, 옵셔널(Optionals)을 풀어버렸다. 그리고 옵셔널이 풀어졌기 때문에 존재 할 수 없는 nil 아이템 또한 사라졌다. 애초에 flatMap 에 사용한 클로져 프로시져에는 옵셔널이나 nil이 파라미터로 넘어오지 않는다는 의미로 볼 수 있다.

중첩 배열 풀어버리기

중첩 배열, 즉 배열 안에 있는 배열(nested arrays)을 단일 배열(single array)로 풀어버릴 수 있다. 아래 예제를 보자.
let nestedItems = [ [1, 2, 3], [4, 5, 6] ]
let flattenNested = nestedItems.flatMap { $0 }
flattenNested
// [1, 2, 3, 4, 5, 6]
nestedItems는 배열을 가지고 있는 배열([[Int]])이다. 이걸 flatMap을 이용해 보면 각 배열 내부의 아이템들이 파라미터로 넘어오게 된다. 즉, 중첩된 배열이 풀어져버린다.

사실 이 부분이 flat이라는 이름에 걸맞는 행위(?)인 것 같은데, 생각(?)보다는 쓸 만 하지 않다. 아래의 경우를 보자.
let complexItems = [ 1, [2, 3], 4, [5, 6, 7, [8, 9]], 10 ]
let flattenComplex = complexItems.flatMap { $0 }
flattenComplex
// [1, [2, 3], 4, [5, 6, 7, [...]], 10]
이 예제에서는 복합형 타입, 즉 AnyObject 형식의 아이템을 가지게 되는 배열([AnyObject])은 전혀 풀어주질 못 한다. 사실 당연하다면 당연한 것이겠지만...

결국 중첩 배열을 풀어버려면 하나의 타입으로 구성된 배열에 한정해야 한다는 말이다.

그래서 뭐에 쓰는거지?

개인적으로 찾아본 특징 중 위 두 가지가 flatMap 의 성격을 가장 잘 보여주는 거라고 생각된다. 왜냐하면 위 두 가지 케이스를 제외하곤 딱히 쓸 만한 곳을 모르겠다.

물론 이는 개인적인 생각일 뿐, 어떤 용도로 쓰이는지 코드를 구경해 봤으면 좋겠다. -_-;;

[관련글] Swift - Collection 타입의 도구들: map, filter, reduce, zip
[관련글] Swift - 클로져(Closures)
[관련글] Swift - 옵셔널(Optionals)
[관련글] 스위프트(Swift) 가이드

댓글 없음 :