[Swift] filter, reduce, map

in sequence protocol

Posted by Kim Heebeom on January 12, 2018

filter

조건에 만족하는 시퀀스 원소들만 추려서 배열로 반환한다.

Declaration func filter(_ isIncluded: (Int) throws -> Bool) rethrows -> [Int]

클로저는 각 원소가 조건을 만족하는지 검사하여 Bool값을 반환한다.

func isEven(value: Int) -> Bool {
    return value%2 == 0
}

let arr = [2, 3, 4, 5, 6]
arr.filter(isEven)
// [2, 4, 6]

정수형 배열 arrisEven 함수를 filter의 파라미터로 사용. filter는 각 원소에 대해 isEven 함수로 조건을 만족하는지 검사한다.

isEven 함수를 클로저 표현식으로 바꾸어 식을 간단하게 만들 수 있다.

arr.filter { (value: Int) -> Bool in
    return value % 2 == 0
}
// [2, 4, 6]

역시 동일한 배열을 반환한다. 이제 가장 간단한 표현식으로 고쳐보면

arr.filter { $0 % 2 == 0 }

위 예제는 Int형 배열을 이용하였지만, 다른 타입의 배열도 이용할 수 있다.

func filter<T>(_ isIncluded: (T) throws -> Bool) rethrows -> [T]

reduce

주어진 클로저를 이용해서 원소들을 결합하는 메소드이다.

Declaration func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result

위에서 처럼 filter를 이용하여 새로운 배열 [2, 4, 6]을 만든다.

그 다음 reduce 메소드를 호출하여 각각의 원소들에 대해서 순차적으로 클로저를 실행하며 결과를 누적한다.

arr.filter { $0 % 2 == 0 }
    .reduce(0) { (result, value) -> Int in result + value }
// 출력 : 12

조금 더 간단하게 바꾸어 보면

arr.filter { $0 % 2 == 0 }
    .reduce(0) { $0 + $1 }

reduce의 첫 번째 파라미터로 주어진 0 은 초기값을 나타내고 클로저의 $0은 최종 결과값을 말한다.

첫 번째 이터레이터에서 나온 결과 값이 두 번째 이터레이터의 첫 번째 파라미터로 전달되는 것이다.

map

시퀀스의 각 원소들에 클로저를 mapping한 배열을 반환한다.

Declaration func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]

let book = ["Operation System", "Swift", "Design Pattern"]

book.map { $0.lowercased() }
// ["operation system", "swift", "design pattern"]
book.map { $0.count }
// [16, 5, 14]

서로 다른 3개의 책을 갖는 book 변수를 선언하였다.

book.map { $0.lowercased() } 은 각 string 원소들을 소문자로 mapping 한 결과값을 반환한다.

동일한 방식으로 book.map { $0.count } 은 각 string 원소들의 길이를 계산하여 새로운 배열 [16, 5, 14] 을 만들어 반환한다.