[JavaScript] L.flatMap, flatMap

2023. 5. 10. 07:18· Node.js/JS
목차
  1. flatMap
  2. 지연 평가가 적용된 L.flatMap
  3. 2차원 배열 다루기

flatMap

flatMap은 최신 자바스크립트 스펙에 등장하는 함수로, map과 flatten을 동시에 수행하는 함수다.

console.log([[1, 2], [3, 4], [5, 6, 7]].flatMap(a => a));
// (7) [1, 2, 3, 4, 5, 6, 7]

이렇게 기본 Array 프로토타입의 flatMap 메서드를 사용하면 하나의 배열로 만들어주며, 함수를 적용한다.

 

이는 배열이 아닌 값이 원소로 들어가도 동일하게 작동한다.

console.log([[1, 2], [3, 4], [5, 6, 7], 8, 9, [10]].flatMap(a => a));
// (10) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

여기서 함수를 다르게 하여 flatMap을 최대한 활용할 수 있다.

console.log([[1, 2], [3, 4], [5, 6, 7]].flatMap(a => a.map(a => a * a)));
// (7) [1, 4, 9, 16, 25, 36, 49]

각 원소에 제곱을 하여, flat과 map을 동시에 실행할 수 있다.

 

사실상 이 함수는 map을 한 배열에 flatten을 한 것과 동일한 것이다.

console.log(flatten([[1, 2], [3, 4], [5, 6, 7]].map(a => a.map(a => a * a))));
// (7) [1, 4, 9, 16, 25, 36, 49]

flat과 map이 공존하여 정적 메서드로 존재하는 이유는 flat과 map이 비효율적으로 사용되기 때문이다.

 

위의 함수의 경우에 map을 통해 모든 값을 순회하면서 함수가 적용된 배열을 반환한다. 그리고 flatten으로 다시 순회를 하면서 배열을 담기 때문에 비효율적이다. 따라서, 이를 한 번에 수행하여 시간 복잡도를 줄이는 것이 좋다. 사실 flatMap과 flatten + map은 시간 복잡도 면에서 차이가 없다.

지연 평가가 적용된 L.flatMap

이터러블을 다룰 수 있으며, 지연평가할 수 있는 flatMap을 만들어 보고자 한다.

더보기
const isIterable = a => a && a[Symbol.iterator];

L.flatten = function *f(iter) {
  for (const a of iter) {
  	if (isIterable(a)) yield *f(a);
    else yield a;
  }
}
L.flatMap = pipe(L.map, L.flatten);
const curry = f =>
  (a, ...fs) => fs.length
  ? f(a, ...fs)
  : (...fs) => f(a, ...fs);
  
const reduce = curry((f, acc, iter) => {
  if (!iter) {
    iter = acc[Symbol.iterator]();
    acc = iter.next().value;
  }
  for (const a of iter) {
    acc = f(acc, a)
  }
  return acc;
};
  
const go = (...fs) => reduce((a, f) => f(a), fs);

const pipe = (...fs) => a => go(a, ...fs);

L.flatMap = curry(pipe(L.map, L.flatten));

이제 함수가 잘 작동하는지 테스트할 수 있다.

const it = L.flatMap(map(a => a * a), [[1, 2], [3, 4], [5, 6, 7]]);

console.log(it.next());
// {value: 1, done: false}
console.log(it.next());
// {value: 4, done: false}
console.log(it.next());
// {value: 9, done: false}
console.log(it.next());
// {value: 16, done: false}
console.log(it.next());
// {value: 25, done: false}
console.log(it.next());
// {value: 36, done: false}
console.log(it.next());
// {value: 49, done: false}
console.log([...it]);
// (7) [1, 4, 9, 16, 25, 36, 49]
const it = L.flatMap(a => a, [[1, 2], [3, 4], [5, 6, 7]]);
console.log([...it]);
// (7) [1, 2, 3, 4, 5, 6, 7]

 최종적으로 바로 평가까지 완료된 함수로 사용하고자 할 때 아래와 같이 마무리할 수 있다.

const flatMap = curry(pipe(L.map, flatten));

flatMap은 원하는 함수와 배열을 인자로 넣어서 해당 함수를 적용시킨 배열을 1차원 배열인 상태로 만들 수 있다는 장점이 있다.

 

예를 들어서 [1, 2, 3]이라는 배열에 range 함수를 적용할 수 있다.

L.range = function *(l) {
  let i = -1;
  while (++i < l) yield i;
}

console.log(flatMap(L.range, [1, 2, 3]));
// (6) [0, 0, 1, 0, 1, 2]

그냥 map을 사용했다면, 2차원 배열로 저장됐을 로직을 1차원 배열을 반환하도록 변경한 것이다.

2차원 배열 다루기

2차원 배열을 flatten이나 flatMap을 통해 다뤄보자.

const arr = [
  [1, 2],
  [3, 4, 5], 
  [6, 7, 8],
  [9, 10]
];

go(arr
  console.log);
  
// (4) [Array(2), Array(3), Array(3), Array(2)]

이 코드를 flatten으로 1차원 배열로 펼쳐줄 수 있다.

go(arr
  flatten,
  console.log);
  
// (10) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

여기에 filter를 붙여 홀수만 출력할 수도 있다.

go(arr,
  flatten,
  filter(a => a % 2),
  console.log);
  
// (5) [1, 3, 5, 7, 9]

이렇게 동작한다는 것은 지연 평가를 적용할 수 있다는 의미이기도 하다.

go(arr,
  L.flatten,
  L.filter(a => a % 2),
  takeAll,
  console.log);
  
// (5) [1, 3, 5, 7, 9]

예를 들어, [1, 2] 원소를 flatten으로 펼친 다음, 1 값이 filter를 거치고, takeAll을 거쳐서 값을 하나 꺼내 출력하고, 2도 마찬가지의 로직을 따른다.


함수 체이닝을 굉장히 많이 사용했던 강의였다. 그래서 이전에 배웠던 curry, reduce, go, pipe가 많이 재등장했다. 이전에 공부했던 함수들을 다시 꺼내어 정리하면서 도움이 많이 됐다. 예전에는 이전 게시물에서 복사 붙여넣기만 했었는데, 이젠 직접 curry, reduce, go, pipe 함수를 작성한다. 점점 더 이해가 되다 보니까 자연스럽게 쓸 수 있어 좋았다. 지금까지의 강의는 대부분 함수를 구현하고, 지연 평가로 전환하며 함수 합성에 적용해보는 것이어서 이런 것들을 연습하고, 실제 구현하는 능력도 기를 수 있는 기회인 것 같다.

 

출처: 인프런 함수형 프로그래밍과 JavaScript ES6+

저작자표시 비영리 (새창열림)

'Node.js > JS' 카테고리의 다른 글

[JavaScript] 이터러블 중심 프로그래밍 실무적인 코드  (0) 2023.05.11
[JavaScript] L.flatten, flatten, L.deepFlat 함수 만들기  (0) 2023.05.09
[JavaScript] L.map, L.filter로 map과 filter 만들기  (0) 2023.05.09
[JavaScript] 함수 합성을 통해 find 함수 만들기  (0) 2023.05.08
[JavaScript] Array.prototype.join 보다 다형성 높은 join 함수  (0) 2023.05.08
  1. flatMap
  2. 지연 평가가 적용된 L.flatMap
  3. 2차원 배열 다루기
'Node.js/JS' 카테고리의 다른 글
  • [JavaScript] 이터러블 중심 프로그래밍 실무적인 코드
  • [JavaScript] L.flatten, flatten, L.deepFlat 함수 만들기
  • [JavaScript] L.map, L.filter로 map과 filter 만들기
  • [JavaScript] 함수 합성을 통해 find 함수 만들기
턴태
턴태
import { Dream } from "future";
턴태
턴태의 밑바닥부터 시작하는 de-vlog
턴태
전체
오늘
어제
  • ROOT (187)
    • Node.js (37)
      • ES6 (1)
      • TypeScript (3)
      • Express.js (16)
      • NestJS (16)
      • JS (24)
    • 프론트엔드 (29)
      • CS (5)
    • 백엔드 (1)
      • 검색 (2)
      • Database (1)
    • 기타 툴 (1)
      • git (1)
    • 데브옵스 & 인프라 (19)
      • Kubernetes (15)
      • Docker (2)
      • Monitoring (1)
      • IaC (1)
    • Algorithm (90)
      • Implementation & simulation (5)
      • Math (4)
      • Brute Force (1)
      • String (0)
      • Graph (5)
      • Recursion & Backtracking (19)
      • Divide & Conquer (2)
      • Dynamic Programming (18)
      • Greedy (13)
      • Priority Queue (2)
      • Binary Search (6)
      • Data Structure (7)
      • Shortest Path (5)
      • Minimum Spanning Tree (1)
      • Sorting (1)
      • Prefix Sum (1)
    • Linux (1)
      • Ubuntu (1)
    • Diary (5)
      • Algorithm (1)
      • Conference (1)
      • Retrospective (3)
    • Book (0)
      • Self-Development (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 백준
  • N과 M
  • Omuk
  • 인프런X디프만
  • 쿠버네티스
  • 자바스크립트
  • dynamic programming
  • node.js
  • 네스트
  • 다이나믹 프로그래밍
  • Kubernetes
  • 함수형 프로그래밍
  • backtracking
  • 오먹
  • Express
  • TypeScript
  • 파이썬
  • Toy Project
  • GREEDY
  • nestjs
  • baekjoon
  • 백트래킹
  • 노드
  • 토이프로젝트
  • 디프만
  • 익스프레스
  • 타입스크립트
  • 인프런
  • python
  • k8s

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.1
턴태
[JavaScript] L.flatMap, flatMap
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.