본문 바로가기
Programming/JavaScript

[JavaScript] Set 사용법

by devpine 2020. 3. 23.
반응형

Set이란?

Set 객체는 중복되지 않는 유일한 값들의 집합입니다. Set 객체는 배열과 비슷하지만 차이점이 존재합니다.

  배열 Set 객체
동일한 값을 중복하여 포함 가능하다. O X
요소 순서가 의미가 있다. O X
인덱스로 요소에 접근할 수 있다. O X

위의 특성으로 보아 Set 객체는 수학적 집합의 특성과 일치하며, 교집합, 합집합, 차집합, 여집합 등을 구현할 수 있습니다.

Set 객체 생성

  • Set 생성자 함수로 Set 객체를 생성합니다.
  • 생성자 함수에 인자를 전달하지 않으면 빈 Set 객체가 생성됩니다.
const set = new Set();

console.log(set); // Set(0) {}
  • Set 생성자 함수는 이터러블을 인수로 전달받아 Set 객체를 생성하는데, 이때 이터러블의 중복된 값은 Set 객체에 저장되지 않습니다.
const set1 = new Set([1, 1, 2, 2, 3]);
const set2 = new Set('aabbcc');

console.log(set1); // Set(3) {1,2,3}
console.log(set2); // Set(3) {"a", "b", "c"}
  • Set 객체의 특성을 사용하여 배열에서 중복된 요소를 제거할 수 있습니다.
const arr = [1, 2, 1, 2, 3, 4, 3];

const uniq = array => [...new Set(array)];

console.log(uniq(arr)); // [1, 2, 3, 4];

요소 개수 확인하기

  • Set.prototype.size 프로퍼티를 사용하여, Set 객체의 요소 수를 반환합니다.
const { size } = new Set([1, 2, 2, 3]);
console.log(size); // 3
  • size 프로퍼티는 setter 없이 getter 함수만 존재하는 접근자 프로퍼티입니다. 그래서 size 프로퍼티에 숫자 할당을 시도해도, Set 객체의 요소 개수는 변경되지 않습니다.
set.size = 10; // size 프로퍼티에 할당을 시도 -> 무시됨
console.log(size) // 3

요소 추가

  • Set.prototype.add 메서드를 사용하여, Set 객체에 요소를 추가합니다. 중복된 요소는 추가되지 않습니다.
const set = new Set();
set.add(1);

console.log(set); // Set(1) {1}
  • add 메서드를 호출한 후에 add 메서드를 연속 호출(method chaining)할 수 있습니다. add 메서드는 새로운 요소가 추가된 Set 객체를 반환하기 때문입니다.
const set = new Set();
set.add(1).add(2);

console.log(set); // Set(2) {1, 2}

  • Set 객체는 자바스크립트의 모든 값을 요소로 저장할 수 있습니다.
const set = new Set();

set
  .add(1)
  .add('a')
  .add(true)
  .add(undefined)
  .add(null)
  .add({})
  .add([])
  .add(()=>{});

요소 존재 여부 확인

  • Set.prototype.has 메서드를 사용하여, Set 객체에 특정 요소가 있는지를 확인합니다.
  • boolean 타입(true/false)의 값을 반환합니다.
const set = new Set([1, 2, 3]);

console.log(set.has(2)); // true
console.log(set.has(0)); // false

요소 삭제

  • Set.prototype.delete 메서드를 사용하여, Set 객체에서 특정 요소를 삭제합니다.
  • 이 때, 삭제하려는 요소의 인덱스가 아닌, 값을 인수로 전달해야 합니다. Set 객체에는 인텍스가 없기 때문입니다.
  • 존재하지 않는 Set 객체의 요소를 삭제 시도하면 무시됩니다.
cosnt set = new Set([1, 2, 3]);

set.delete(2); // 요소 2 삭제
console.log(set); // Set(2) {1, 3}

set.delete(1); // 요소 1 삭제
console.log(set); // Set(1) {3}

set.delete(0); // 요소 0 삭제 시도 -> 무시됨
console.log(set); // Set(1) {3}

요소 일괄 삭제

  • Set.prototype.clear 메서드를 사용하여, Set 객체에서 모든 요소를 삭제합니다.
const set = new Set([1, 2, 3]);

set.clear();
console.log(set); // Set(0) {}

요소 순회

forEach(data, key, array) 메소드

  • Set.prototype.forEach 메서드를 사용하여, Set 객체의 요소를 순회합니다.
  • forEach 메서드의 콜백 함수 내부에서 this로 사용될 객체를 인수로 전달한다.
  • 이때 콜백 함수는 3개의 인수를 전달받는데, 1번째 인수와 2번째 인수는 같은 값이다. Array.prototype.forEach 메서드와 인터페이스를 통일하기 위함이다.
    • 1번째 인수: 현재 순회 중인 요소값
    • 2번째 인수: 현재 순회 중인 요소값
    • 3번째 인수: 현재 순회 중인 Set 객체
const set = new Set([1, 2, 3]);

set.forEach((value, value2, set) => {
  console.log(value, value2, set);
});

/*
1 1 Set(3) {1, 2, 3}
2 2 Set(3) {1, 2, 3}
3 3 Set(3) {1, 2, 3}
*/
  • Set 객체는 이터러블이므로, for ... of 문으로 순회할 수 있고, 전개연산자(spread 문법) 사용이 가능하고, 배열 디스트럭쳐링(destructuring)의 대상이 될 수 있다.
const set = new Set([1, 2, 3]);

// Set 객체는 Set.prototype의 Symbol.iterator 메소드를 상속받는 이터러블이다.
console.log(Symbol.iterator in set); // true

// for...of 문 순회
for (const v of set) {
  console.log(v); // 1 2 3
}

// spread
console.log(...set); // [1, 2, 3]

// destructure
const [a, ...rest] = set;
console.log(a, rest); // 1, [2, 3]

집합 연산

  • 교집합
// 방법 1
Set.prototype.intersection = function (set) {
  const result = new Set();
  
  for (const v of set) {
    // 공통되는 요소라면 교집합의 대상
    if (this.has(v)) result.add(v);
  }
  
  return result;
}

// 방법 2
Set.prototype.intersection = function (set) {
  return new Set([...this].filter(v => set.has(v)));
}

const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 4]);

// setA, setB의 교집합
console.log(setA.intersection(setB)); // Set(2) {2, 4}
  • 합집합
// 방법 1
set.prototype.union = function (set) {
  // this(Set 객체)를 복사
  const result = new Set(this);
  
  for (const v of set) {
    // 모든 요소는 합집합의 대상
    result.add(v);
  }
  
  return result;
}

// 방법 2
set.prototype.union = function (set) {
  return new Set([...this, ...set]);
}

const setA = new Set([1, 2, 3, 4]);
const setB = new Set([1, 3]);

// setA, setB의 합집합
console.log(setA.union(setB)) // Set(4) {1, 2, 3, 4}
  • 차집합
// 방법 1
Set.prototype.difference = function (set) {
  // this(Set 객채)를 복사
  const result = new Set(this);
  
  for (const v of set) {
    // 한 집합에는 존재하지만, 다른 집합에는 존재하지 않는 요소라면 차집합의 대상
    result.delete(v);
  }
  
  return result;
};

// 방법 2
Set.prototype.difference = function (set) {
  return new Set([...this].filter(v => !set.has(v)));
};

const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 4]);

console.log(setA.difference(setB)); // Set(2) {1, 3}
console.log(setB.difference(setA)); // Set(0) {}
  • 부분집합(subset), 상위집합(superset)
// 방법 1
Set.prototype.isSuperset = function (subset) {
  for (const v of subsest) {
    // superset의 모든 요소가 subset을 포함하는지 확인
    if(!this.has(v)) return false;
  }
  return true;
}

// 방법 2
Set.prototype.isSuperset = function (subset) {
  const supersetArr = [...this];
  return [...subset].every(v => supersetArr.includes(v));
}

const setA = new Set([1, 2, 3, 4]);
const setA = new Set([1, 2]);

console.log(setA.isSuperset(setB)); // true
console.log(setB.isSuperset(setA)); // false


✏️ 모던 자바스크립트 Deep Dive 도서를 읽고 개인적으로 공부하며 정리한 내용입니다.
반응형

댓글