본문으로 건너뛰기
개발 머꼬
개발 노트JavaScript
hohyeon.dev35

교집합을 직접 구현하지 않아도 되는 Set 메서드와 Iterator 헬퍼

  • #Engineering Note
  • #ES2025
  • #JavaScript

문제 발생

두 사용자 그룹의 교집합을 구하려고 매번 이런 코드를 썼습니다. 짧지만 has를 어느 쪽에 호출하는지 헷갈리기 쉽고, 합집합·차집합까지 필요해지면 유틸 파일이 하나 생깁니다.

const intersection = new Set([...admins].filter((id) => editors.has(id)));

제너레이터를 필터링할 때는 문제가 더 큽니다. map이나 filter를 쓰려고 Array.from()으로 펼치는 순간, 앞의 몇 개만 필요한 경우에도 전체를 메모리에 올리게 됩니다.

const firstTen = Array.from(readHugeLog())   // 전부 펼친 다음
  .filter((line) => line.level === "error")
  .slice(0, 10);                             // 10개만 쓴다

원인 분석

두 기능 모두 표준에 없어서 각자 구현하거나 lodash 같은 라이브러리를 얹어 왔습니다. ES2025(16번째 판, 2025년 6월 25일 승인) 에서 둘 다 표준이 됐습니다.

Set 메서드union, intersection, difference, symmetricDifference, isSubsetOf, isSupersetOf, isDisjointFrom. 2024년 6월부터 Baseline입니다.

Iterator 헬퍼 — 이터레이터에 직접 map, filter, take, drop, flatMap, reduce, toArray 등을 걸 수 있습니다. 배열 메서드와 결정적으로 다른 점은 게으르다(lazy) 는 것입니다. 값을 하나 요청할 때마다 하나씩만 계산하므로, take(10)이면 원본에서 딱 필요한 만큼만 읽습니다.

해결 방안

  1. 집합 연산은 Set 메서드를 그대로 씁니다. 읽는 사람이 의도를 바로 알 수 있습니다.
const admins = new Set(["a", "b", "c"]);
const editors = new Set(["b", "c", "d"]);

admins.intersection(editors);        // Set { 'b', 'c' }
admins.union(editors);               // Set { 'a', 'b', 'c', 'd' }
admins.difference(editors);          // Set { 'a' }
admins.symmetricDifference(editors); // Set { 'a', 'd' }
admins.isDisjointFrom(editors);      // false
  1. 큰 시퀀스는 Iterator 헬퍼로 필요한 만큼만 읽습니다.
const firstTen = readHugeLog()
  .filter((line) => line.level === "error")
  .take(10)
  .toArray();          // 에러 10개를 찾는 즉시 읽기를 멈춘다
  1. 끝이 없는 시퀀스에도 쓸 수 있습니다. 배열로는 애초에 불가능했던 형태입니다.
function* naturals() { let n = 1; while (true) yield n++; }
naturals().map((n) => n * n).take(5).toArray(); // [1, 4, 9, 16, 25]
  1. 지원 범위를 확인합니다. Set 메서드는 Baseline 2024라 최신 브라우저에서는 안전하지만, 구형 환경을 지원해야 한다면 core-jses-shims 폴리필이 필요합니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.