본문 바로가기

Swift

Map, Filter, Reduce - 컬렉션타입을 더 쉽고 편리하게!


[이미지 출처 : https://www.joshmorony.com/filtering-mapping-and-reducing-arrays-in-ionic-2/]



Swift에는 컬렉션타입 사용할 때 매우 편리하게 쓸 수 있는 몇 가지의 함수를 제공한다.

루비 개발자라면 익숙한 Map, Filter, Reduce가 그것이다.


이 3가지 함수는 데이터를 주로 처리하는 작업의 양을 획기적으로 줄여주기 때문에 필수적으로 익혀두는 것이 좋다.




Map


맵은 컬렉션타입을 순환하여 특정 값을 결과값으로 리턴해 준다. 예제를 보자.


let number: Array = [12345]


number 배열은 총 5개의 값을 가지고 있다. 만일 해당 값에 일괄적으로 * 2를 하고 싶다면


printnumber.map( { (value: Int) -> Int in return value * 2 } ) )

// [2, 4, 6, 8, 10]


이런식으로 사용할 수 있다. 맵은 내부 블록에서 코딩된 내용을 "처리한 후의 값"을 리턴해 준다.


printnumber.map( { (value: Int) -> String in return "$" + String(value) } ) )

// ["$1", "$2", "$3", "$4", "$5"]


이런식으로 활용도 가능하다.




그럼 Dictionary의 경우에는 어떨까?

let cars: Dictionary = [

    "BMW" : 1000,

    "Benz" : 2000,

    "Lamborghini" : 3000

]


이런 모양의 Dictionary가 있다고 하자. 이럴경우에는 map의 인자가 두개가 된다.


printcars.map( { (val1: String, val2: Int) -> Int in return val2 * 2 } ) )

// [2000, 4000, 6000]


만일 차의 이름만 뽑고 싶다면


printcars.map( { (val1: String, val2: Int) -> String in return val1 } ) )

// ["BMW", "Benz", "Lamborghini"]


이런식으로 하면 된다.


printcars.map( { (val1: String, val2: Int) -> String in return val1 + ":" + String(val2) } ) )

// ["BMW:1000", "Benz:2000", "Lamborghini:3000"]


이렇게 응용도 가능하다.



주로 Map은 기본 데이터를 컬렉션타입으로 저장을 한 후, 특정 뷰에 "가공된" 값을 사용해야할때 요긴하게 쓸 수 있다.







Filter


다음으로 Filter 함수가 있다. 이 함수는 이름을 보면 쉽게 기능을 예상 가능하듯이 컬렉션타입 내의 특정 조건의 값만 리턴해 준다.


printnumber.filter( { (value: Int) -> Bool in return (value % 2 == 0) } ) )

// print = [2, 4]


만일 number 배열에서 2로 나눠서 0인 것만 뽑아 내기 위해서는 위와 같이 사용을 하면 된다.


printcars.filter( { (val1: String, val2: Int) -> Bool in return val1 == "Benz" } ) )

// print = [(key: "Benz", value: 2000)]


만일 벤츠만 리턴시키고 싶다면 Dictionary에서는 이와 같이 사용하면 된다.






Reduce


만일 컬렉션타입 내부의 값을 더해서 총합을 보여줘야할 때 쉬운 방법이 없을까? 그때 바로 Reduce 함수를 사용하면 된다.


printnumber.reduce(0, { (s1: Int, s2: Int) -> Int in return s1 + s2 }) )

// print = 15


Reduce함수는 내부의 연산 코드를 기반으로된 값을 리턴해 준다. 위 코드는 number의 값을 모두 더하는 코드이다.


printnumber.reduce(10, { (s1: Int, s2: Int) -> Int in return s1 * s2 }) )

// 10 * 1 * 2 * 3 * 4 * 5

// print = 1200


이렇게 사용도 가능하다.

만일 Dictionary의 경우에는 어떻게 해야할까? 여러가지 방법이 있지만 아래와 같은 방법이 편리하다.


let dicValues = cars.map( { (val1: String, val2: Int) -> Int in return val2 } )

printdicValues.reduce(0, { (s1: Int, s2: Int) -> Int in return s1 + s2 }) )

// print = 6000


위 내용은 먼저 dicValues에 자동차의 가격을 배열로 저장한다. 결과값은 [1000, 2000, 3000]이 될 것이다.

그 다음 reduce를 이용해서 dicValues의 값들을 합한다.







이 3가지의 함수의 장점은 서로 합체(?)가 가능하다는 점이다. 마지막 Dictionary의 합을 구한것처럼 map과 filter와 reduce 값을 조합해서 쓸 수 있다. 다시 Dictionary를 보자.


let cars: Dictionary = [

    "BMW" : 1000,

    "Benz" : 2000,

    "Lamborghini" : 3000

]


만일 여기서 BMW와 Benz 두 차의 가격만 더하고 싶다고 해 보자. 


let procCar = cars.filter( { (val1: String, val2: Int) -> Bool in return (val1 == "Benz" || val1 == "BMW") } )

// [(key: "BMW", value: 1000), (key: "Benz", value: 2000)]


먼저 filter를 이용해서 두 차만 뽑아 낸다.


let carPrice = procCar.map( { (val1: String, val2: Int) -> Int in return val2 } )

// [1000, 2000]


그 후 차의 가격만 map을 이용해서 뽑아낸다.


let SumCarPrice = carPrice.reduce(0, { (s1: Int, s2: Int) -> Int in return s1 + s2 } )

// 3000


마지막으로 reduce를 이용해서 차의 가격을 합하면 끝!






참 쉽죠?