고차함수

apwierk·2022년 5월 27일
0

개인 공부

목록 보기
4/20

고차함수

정의

  • 클로저를 인자로 받는 함수

종류

  • Transforming a Sequence : 시퀀스 내용을 변형하는 함수
  • Sorting Elements : 시퀀스의 내용 변경 없이 정렬만 해주는 함수
  • Iterating Over a Sequence's Elements : 시퀀스의 내용을 반복하여 접근하는 함수

시퀀스란?
프로토콜
자기 자신의 요소 값들이 반복적, 순차적 접근되는 것을 제공하는 타입
시퀀스 프로토콜을 준수하는 타입은 for-in 루프로 순회할 수 있음


Map

정의

  • 컨테이너 내부의 기존 데이터를 변형하여 새로운 컨테이너를 생성
  • Collection에 정의되어있으므로 CollectionType이라면 모두 사용이 가능.

for - in 으로 구현하는것과 차이는 없지만

  • 코드의 간결성
  • 재사용성 증가
  • 컴파일러 최적화


위와 같이 전달인자로 함수(컨테이너 내부 데이터를 변경하는)를 받는다.
또한 아래와 같이 후행 클로저로 사용할 수 있다.

let numbers = [1, 2, 3, 4, 5]
for number in numbers {
	number += 1
}
let numbers = [1, 2, 3, 4, 5]
let number = numbers.map { $0 + 1 }

map


Filter

정의

  • 말그대로 필터역할 (내부의 값을 추출할 때)
  • bool 을 반환 값으로 가진 클로저를 인자로 갖는다.

    반복문 + 조건문 형식이다.

var filtered: [Int] = [Int]()

for num in nums {
    if num % 2 == 0 {
        filtered.append(num)
    }
}
print(filtered)
let nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let evenNums = nums.filter { num in
    return num % 2 == 0
}
print(evenNums)
let oddNums = nums.filter { $0 % 2 == 1 }
print(oddNums)

reduce

정의

  • 주어진 클로저를 사용하여 시퀀스의 요소를 결합한 결과를 반환합니다.

기능

  • 컨테이너 내부의 데이터를 하나로 통합하는 메소드
  • 기존 컨테이너에서 내부의 값들을 결합하여 새로운 값을 만듭니다.
  • 즉, 전체 시퀀스의 요소에서 단일 값 생성 가능

구조

func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
  • initialResult
    - 초기 누적 값으로 사용할 값
    - initialResult는 클로저가 처음 실행될 때 nextPartialResult에 전달
  • nextPartialResult
    - ResultnextPartialResult 클로저의 다음 호출에 사용되거나 호출자에게 반환될 누적 값
    - Element → 시퀀스 요소
    - ResultElement를 새로운 누적 값으로 결합하는 클로저.
    - 이해가 잘 되지 않았다면, 아래의 표현 방법을 통해 자세히 알아보도록 한다
  • 반환 값
    - 최종 누적 값
    - 시퀀스에 요소가 없으면 결과는 initialResult

메서드 내부 과정

  • nextPartialResult 클로저는 initialResult와 숫자의 첫 번째 요소로 호출돼 연산 후 반환
  • 클로저는 이전 호출의 반환 값과 시퀀스의 각 요소와 함께 반복적으로 다시 호출
  • 시퀀스가 소진되면 클로저에서 반환된 마지막 값이 호출자에게 반환

표현 방법

// 방법 1 : 기본
// 초깃값이 0이고 someNumbers 내부의 모든 값을 더합니다.
        
let numberArray1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let sum: Int = numberArray1.reduce(0, { (result: Int, currentItem: Int) -> Int in
	print("result: \(result) / currentItem: \(currentItem)")
	return result + currentItem
})

print(sum)  // 55
        
// 방법 2 : 매개변수, 반환 타입, 반환 키워드(return) 생략, 후행 클로저
// 초깃값이 3이고 someNumbers 내부의 모든 값을 더합니다.
        
let numberArray2 = [1, 2, 3, 4, 5]
let multiplicationFromTen = numberArray2.reduce(10) { $0 * $1 }
        
print(multiplicationFromTen) // 1200
        
  • 첫번째 매개변수 result → 초깃값으로부터 출발하여 마지막 요소까지 순회한 결과값
  • 두번째 매개변수 currentItem → 현재 순회하고 있는 요소의 값
  • 반환 값 return result + currentItem → 현재까지 더해진 결과값에 이번 요소의 값을 더함 의미

FlatMap

정의

  • 여러 배열을 하나의 배열로 결합하는 작업을 수행하여 결과로 새 배열을 반환함
  • 즉, 이름처럼 2차원이었던 배열을 1차원으로 평평하게(flat) 만들어줌
let numbers = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
let flatMapTest = numbers.flatMap{ $0 }
print(flatMapTest) // [1, 2, 3, 4, 5, 6, 7, 8, 9]

선언

func flatMap<SegmentOfResult>(_ transform: (Self.Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence

CompactMap

정의

  • 반환되는 결과 중 nil이 아닌 결과만 걸러서 새 배열을 반환함

기능

  • 옵셔널 바인딩해줄 때 사용 → swift 4.1 이전엔 flatMap 기능이었음
let numbers = ["42", "19", "notANumber"]
let compactMapTest = numbers.compactMap{ Int($0) }
print(compactMapTest) // [42, 19]

let numbers = [0, 2, nil , Optional(4)]
        let compactMapTest = numbers.compactMap{ $0 }
        print(compactMapTest) // [0, 2, 4]
  • 옵셔널타입의 배열에서 nil이 아닌 값만 추출하고 싶을 때 사용
let numbers = [1,nil, 2,nil, 3, 4,nil]
let compactMapTest = numbers.compactMap { $0 }
print(compactMap) // [1, 2, 3, 4]

선언

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

Map, FlatMap, CompactMap

공통점

  • 각 요소의 값을 변경시켜 새로운 배열로 만들어 줌 → 정의

차이점

  • Map : 각 요소의 값을 변경시켜 새로운 배열로 만들어 반환
  • FlatMap : 배열의 요소 타입이 옵셔널이라면, nil을 제거하고 옵셔널 바인딩을 한 결과를 배열로 만들어 반환
  • FlatMap : 2차원 배열이면서 요소 타입이 옵셔널이 아니라면, 배열의 요소들을 1차원으로 합친 배열을 반환하고 nil의 제거와 옵셔널 바인딩은 하지 않음
  • CompactMap: 1차원 배열에서 각 요소에 대해 nil을 제거하고 옵셔널 바인딩을 한 결과를 배열로 만들어 반환

정리

  • 새로운 배열을 만들고 싶으면 Map 사용
  • 배열을 평평하게 해주고 싶으면 FlatMap 사용
  • 옵셔널 바인딩이 필요하다면 CompactMap 사용

반복문/조건문 vs 고차함수

반복문/조건문이 있음에도 고차함수를 활용하면 좋은점이 있나요? 있다면 어떤점이 좋은지, 아니라면 어떤 단점이 있는지 이야기해봅시다.

장점

  • 축약인자 사용으로 가독성이 좋아진다.
  • for-loop를 사용해서 데이터를 변경시, 다중 스레드 환경에서 데이터레이스가 발생하면 의도한 결과가 도출 되지 않을 수 있다. 고차함수
  • 컴파일러 최적화 측면에서 성능적으로 좋다고 한다.
  • 상수로 선언 가능하다.

단점

  • 고차함수를 사용하면 오버헤드가 발생할 수 있다.
  • 배열 인덱스 중간에 나올 수 없다. continue, return 를 이용할 수 없고, 결과 값만 받게 된다.

참고
시퀀스

profile
iOS 꿈나무 개발자

0개의 댓글