es6 reduce로 배열을 2차원 배열로 변환

TR;DL

  • 안일한 for문은 시간 복잡도를 상승시킨다.
  • 반복문을 지양하고 함수형 프로그래밍을 고집하는 것이 항상 옳은 것은 아니다.
  • 주어진 배열의 요소가 아닌 배열의 구조가 바뀔 때에는 reduce가 용이하다.
  • reduce의 첫번째 매개변수에 들어가는 함수 인자는 세번째 매개변수로 index를 가진다.
  • spread 연산자는 Deep Copy를 해주지 않는다. (정확히는 가장 상위의 깊이에서만 Deep Copy가 이루어진다)

썰풀기전에

어느 고마우신 분께서 react 커뮤니티에 내 글을 올려주셔서 오늘 하루 방문자가 지금까지 누적된 수의 두배였는데, 물 들어올 때 노 저을 형편은 못 되고 최근에 고민했던 문제를 간단하게 접근해볼까 한다.
React에서 컴포넌트를 배열 요소로 가지고 있는 배열을 다룰 때가 많다. 이번 경우 컴포넌트를 4개까지만 같은 행에 나열하고 그 후 다음 행에서 또 4개를 나열해야 하는 경우가 생겨서 1차원 배열을 배열 내부에 또 배열이 있는 2차원 배열로 재구성해야 했다. (이걸 2차원 배열이라고 부르는 거 맞지? 과거 C 공부하던 거 떠오르네)

예시

1부터 11까지의 숫자를 나열한 1차원 배열이 있을 때, 배열 요소로 1-4, 5-8, 9-11를 나열한 배열을 가지는 2차원 배열로 바꾸고자 한다.

반복문으로 변환하기

사실 이번 경우 반복문을 써도 크게 상관은 없는 게, 반복문의 가독성이 나쁜 것도 아니고 내부에서 특별한 부수효과가 생기는 것도 아닐 뿐더러 시간 복잡도도 n으로 준수한 편이다.
하지만 반복문은 까딱하면 이중 반복문을 구성하여 n제곱의 시간 복잡도를 가지는 경우가 있으므로 안일하게 반복문을 구성하지 않도록 주의해야 한다. 일단 내가 그런 안일한 반복문을 많이 만든다(...)

reduce 메소드로 변환하기

요즘 함수형 프로그래밍에 부쩍 관심이 많아졌는데, 그로 인해 멀쩡한 반복문을 건드려서 함수형 프로그래밍에서 흔히 쓰이는 메소드들로 바꾸거나 하는 일들을 많이 저지른다.
결국 지금의 이 상황도 반복문이 쓰기 싫어 reduce를 사용하고야 말겠다는 나의 아집으로 발생한 것인데, 함수형 프로그래밍이 테스트하기도 좋고 코드 구조가 선언형으로 이루어져서 가독성도 상승하기는 하나 성능상의 문제가 없는 반복문을 함수형 프로그래밍으로 구현하는 것은 어찌보면 안해도 되는 일을 굳이 해내는 비효율적인 작업으로 볼 수도 있다.
180404 추가내용
아침에 샤워하다가 떠오른 건데, React 는 서버에서 받아온 배열을 map 메소드를 이용하여 컴포넌트를 wrapping 해주는 경우가 많다. es6의 map 메소드와 reduce 메소드는 chaining이 가능하기 때문에, React 개발에서는 for문을 reduce 메소드로 재구현할 경우 선언형 구조로 가독성을 살릴 수 있는 이점이 있을 것이다.
어쨌거나 reduce라는 array 타입의 메소드는 map이나 filter에 비해 처음에는 난해하고 쓸 일이 별로 없어 보인다.
그런데 익숙해지면 reduce 메소드를 통해 배열 요소를 가지고 json 오브젝트나 Map을 만든다거나, 배열 요소를 다 더한 값을 구하는 등 기존에 주어진 배열의 형태를 손쉽게 바꾸는 것이 가능하다.
이 코드에서 눈여겨 볼 점은 reduce 메소드의 첫번째 인자로 들어가는 함수의 세번째 인자가 arrayindex라는 것과, 그리고 if문에서 해당 index의 배열 요소가 비어있으면 빈 배열로 초기화하는 작업이다.
빈 배열로 초기화해주지 않으면 다음 행에서 number값을 추가하는 작업에서 에러가 발생하기 때문이다.
참고로, immutable하게 작업하고 싶어서 push 같은 메소드를 사용하지 않고 spread 연산자인 ... 를 사용했는데, 이건 사실 가장 상위 단계의 깊이에서만 Deep Copy가 이루어지기 때문에 지금처럼 배열 요소가 배열인 경우에는 배열 또한 object이기 때문에 배열 요소인 배열들은 Shallow Copy가 된다.