[iOS] Swift Algorithm

Updated:

Swift Algorithms

  • Swift Algorithm 은 오픈소스 패키지이다.
  • Swift Algorithm에 내장된 알고리즘 기능을 사용하면 코드를 더 간결하게 작성할 수 있다.

Swift Algorithm이 제공하는 알고리즘 메서드를 살펴보기 전에 Swift Standard Library가 제공하는 기본 알고리즘 메서드를 살펴보도록 하자.

map

아래처럼 채팅방을 구성한다고 해보자. 흔히 많이 사용하는 mapfor 보다 일반적인 상황에서 더 간결한 코드를 보여줄 수 있고, 성능면에서도 우수하다. 이유는 map 은 배열 사이즈 재설정을 위한 중간 할당을 하지않고 공간을 재사용하기 때문이다.

1

compactMap

위의 채팅방(사진)에서 사진들만 모으는 코드는 다음과 같이 역시 간결하게 나타낼 수 있다.

message가 사진이면 이를 모은다. 일반적인 for 문보다 filtermap으로 간결하게 나타낼수 있다.

2

하지만 위의 코드를 compactMap으로 처리 가능하다. compactMap은 nil인 요소를 제외한 요소들로 이루어진 배열을 반환해준다.

3

joined, flatMap

하나의 요소를 배열로 mapping 해주는 주는 코드를 살펴보자.

4

하지만 위의 여러 배열들을 하나로 묶어주고 싶다면 어떻게 해야 할까? joined() 를 사용하면 된다.

5

그리고 위의 구현을 flatMap 으로 간단히 처리 가능하다.

6

prefix, suffix

배열의 가장 마지막 요소들만을 보여주고 싶은 코드를 살펴보자. prefix 는 요소의 가장 앞부분만을 반환한다.

7

반면 suffix 는 배열의 가장 뒷부분을 보여준다. 결론적으로 위와 동일한 결과를 보여주며 같은 결과라도 다른 알고리즘을 적용하여 유동적으로 대응할 수 있다.

8

알고리즘 성능

알고리즘의 각 chain(메서드)에서 중간 배열을 할당한다면, 일반 반복문보다 느릴수 있다. 하지만 swift에서는 보다 효율적으로 이 문제를 해결하고 있다.

  • joined() 는 배열을 메모리에 새로 할당하지 않고 FlattenSequence를 반환한다. 여기서 FalttenSequencelazy adaptor로 불린다. 이는 배열처럼 사용되지만 한번 더 감싼 wrapper인 셈이다. 그렇기에 생성하기 위한 비용이 들지 않아 효율적이다. 게다가 “lazy” 하기 때문에 사용이 될때 할당이 된다.
  • 그 결과, FlattenSequence와 같은 lazy adaptor는 알고리즘 체인이 성능면에서 우수할 수 있도록 해준다.
  • 아래의 코드에서는 바로 PhotoItem으로 반환되지 않고 ArraySlice로, reversedCollection으로 wrrapping 된다.

9

  • compactMap 앞에 lazy를 적용하면 lazy하게 만들어 줄수 있다. lazy 는 매우 큰 컬렉션에서 적은 수의 요소들만 사용하고자 할때 유용하다.

10

  • 반면 그럼에도 배열이 필요하거나 사용하고 싶다면 Array로 감싸면 된다.

11

Swift Algorithm Package

Swift Algorithm Package는 Swift Standard Library가 아직 제공하지 않는 알고리즘 기능을 제공한다.

12

Swift Algorithm 이 제공하는 몇몇 interation 관련 알고리즘 메서드들은 다음과 같다.

windows(ofCount: Int)

컬렉션 요소들을 하나씩 전진하여 특정 count만큼 반복적으로 잘라 각각 배열로 반환해준다. 위에서 설명했듯이 subsequence를 반환하기 때문에 메모리에 공간을 할당하지 않는다.

13

adjasonedPairs()

windows(ofCount: Int) 와 기능은 비슷하지만 subsequence가 아닌 tuple을 반환한다.

14

chunks(ofCount: Int)

windows(ofCount: Int)와 기능은 비슷하지만 요소들을 하나씩 전진시켜 자르지 않고, count만큼 컬렉션에서 요소들을 잘라 반환한다. 컬렉션의 모든 요소가 count만큼 알맞게 나눠지지 않으면 나머지요소들이 반환된다.

15

chunked(on:)

컬렉션의 요소들을 돌며 특정 옵션에 맞는지에 대한 bool 값과 그에 대한 요소들로 구성된 배열의 튜플을 반환한다. 다음은 chunked(on:)을 사용하여 여러 숫자의 요소로 구성된 컬렉션에서 연속되는 소수의 요소들을 배열로 묶어 반환하는 예시이다.

16

이와 다른 옵션으로 이전 값과 현재 값이 다른지에 대한 로직을 만들때 chunked(on:)을 사용할 수 있다.

17

위의 지식을 바탕으로, 컬렉션에서 현재 요소가 생성된 시간과 이전에 생성된 요소의 시간차가 1시간 이내인 요소들을 분리해 배열로 만들고 그 사이에 각 배열들의 마지막 요소를 삽입해 다시 합치는 로직을 작성해 보자.

우선 컬렉션의 요소들중 각 시간차가 한시간 이내인 것들을 묶어 각 배열로 만들기 위해 chunked를 사용한다.

여기서 사용할 chunked는 predicate, 즉 조건을 사용하여 요소들을 분리해 배열로 만들 수 있다.

18

그 이후 joined 를 사용하여 시간단위로 요소들이 분리된 배열들 사이에 각 배열의 마지막 요소를 삽입해 합쳐준다.

19

그리고 맨 앞에 lazy를 적용해줄 수가 있다.

20

주의할 점이 있는데, lazy가 언제나 해결책이 될수는 없다는 점이다. 시퀀스를 한번만 사용해야 한다면 lazy는 효율적으로 사용될 수 있지만 그렇지 않고, 시퀀스를 반복적으로 사용해야 하면 다음과 같은 코드는 mapping, chunking, joining을 매번 반복하게 되고 이는 비용을 크게 소모한다.

21

이럴 경우는 Array로 한번 감싸주면 효율적으로 작업을 이어나갈 수 있다.

22

이처럼 Swift Standard Library와 Algorithm Package에서 제공하는 알고리즘 기능은 SequenceCollection Protocol을 따르는 ArrayString 같은 타입들에서 사용가능하다.

Categories: ,

Updated:

Leave a comment