본문 바로가기
Programming/JavaScript

[ 모던 자바스크립트 스터디 ] Set (add, delete, forEach, clear ...)

by 코뮤(commu) 2022. 10. 31.
728x90
반응형

Set

 

Set 객체는 중복되지 않는 유일한 값들의 집합니다.

Set 객체는 요소 순서에 의미가 없고, 인덱스로 요소에 접근할 수 없다.

 

 

Set의 특성은 수학적 집합의 특성과 일치한다.

Set을 통해 교집합, 합집합, 차집합, 여집합 등을 구현할 수 있다.

 

 

Set 객체의 생성

Set 생성자 함수로 생성하며, 인수를 전달하지 않으면 빈 Set 객체가 생성된다.

 

const set = new Set();
console.log(set); // Set(0) {}

const set1 = new Set([1, 2, 3, 4]);
console.log(set1); // Set(3) {1, 2, 3}

const set2 = new Set('hello');
console.log(set2); // Set(4) {"h", "e", "l", "o"}

 

Set 생성자 함수는 이터러블을 인수로 전달받아 Set 객체를 생성하는데,

이때 이터러블의 중복된 값은 Set 객체에 요소로 저장되지 않는다.

 

 

이를 이용해 배열에서 중복된 요소를 제거할 수 있다.

 

const uniq = array => [...new Set(array)];
console.log(uniq([2, 1, 2, 3, 4, 3, 4])); // [2, 1, 3, 4]

 

 

요소 개수 확인

 

Set.prototype.size 프로퍼티를 사용한다.

 

const {size} = new Set([1, 2, 3, 4]);
console.log(size); // 3

 

 

요소 추가

 

Set.prototype.add 메서드를 사용한다.

 

const set = new Set();
set.add(1);

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

 

 

add 메서드는 새로운 요소가 추가된 Set 객체를 반환하기 때문에

메서드 체이닝을 활용할 수 있다.

 

set.add(1).add(2)

 

 

일치 비교 연산자 === 는 NaN 과 NaN을 다르다고 평가하지만,

Set 객체는 NaN 과 NaN을 같다고 평가해 중복 추가 되지 않는다.

0과 -0 도 중복추가되지 않는다.

 

 

요소 존재 여부 확인

 

Set 객체에 특정 요소가 존재하는지 확인하려면 Set.prototype.has 메서드를 사용한다.

 

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

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

 

 

요소 삭제

 

Set.prototype.delete 메서드를 사용한다.

인덱스가 아닌 삭제하려는 요소값을 인수로 전달해야한다.

(인덱스를 갖지 않기 때문에)

 

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

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

// 존재하지 않는 요소 삭제 시 에러 없이 무시됨
set.delete(0);
console.log(set); // Set(2) {1, 3}

// 불리언 값을 반환하기에 메서드 체이닝 불가능함.

 

 

요소 일괄 삭제

 

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

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

 

clear 메서드는 언제나 undefined 를 반환한다.

 

 

요소 순회

 

Set.prototype.forEach 메서드를 사용한다.

Set.prototype.forEach 메서드는 Array.prototype.forEach 메서드와 유사하게

콜백 함수와 forEach 메서드의 콜백함수 내부에서 this 로 사용될 객체를 인수로 전달한다.

 

이때 콜백함수는 아래와 같은 인수 3개를 전달받는다.

 

  1. 현재 순회중인 요소값
  2. 현재 순회중인 요소값
  3. 현재 순회중인 Set 객체 자체

 

1번과 2번이 같은 값이라 이상하게 느껴질 수도 있지만,

이건 단지 Array.prototype.forEach 메서드와 인터페이스를 통일하기 위함이고 별 의미는 없다.

 

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

set.forEach((v, v2, set) => console.log(v, v2, set));

 

 

 

 

Set 객체는 이터러블이다. ( for ... of 문으로 순회 가능, 스프레드 문법과 배열 디스트럭처링 대상 가능)

 

const set = Set([1, 2, 3]);

console.log(Symbol.iterator in set); // true

for (const value of set) {
	console.log(value); // 1 2 3
}

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

 

 

집합 연산

 

Set 객체는 수학적 집합을 구현하기 위한 자료다.

따라서 Set 객체를 통해 교집합, 합집합, 차집합 등을 구현할 수 있다.

 

 

교집합

 

집합 A와 집합 B의 공통 요소로 구성된다.

 

Set.prototype.intersection = function (set) {
	const result = new Set();
    
    for (const value of set) {
    	if (this.has(value)) result.add(value);
    }
}

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

console.log(setA.intersection(setB)); // Set(2) {2, 4}
console.log(setB.intersection(setA)); // Set(2) {2, 4}

 

아래와 같은 방법도 가능하다.

 

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

 

 

합집합

 

A와 B의 중복 없는 모든 요소로 구성된다.

 

Set.prototype.union = function (set) {
	const result = new Set();
    
    for (const value of set) {
    	result.add(value);
    }
}

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

console.log(setA.union(setB)); // Set(4) {1, 2, 3, 4}
console.log(setB.union(setA)); // Set(4) {2, 4, 1, 3}

 

아래와 같이 구현할 수도 있다.

 

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

 

 

 

차집합

차집합 A-B는 A에는 존재하지만 B에는 존재하지 않는 요소로 구성된다.

 

Set.prototype.difference = function (set) {
	// this(Set 객체) 복사
	const result = new Set(this);
    
    for (const value of set) {
    	result.delete(value);
    }
}

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

console.log(setA.difference(setB)); // Set(2) {1, 3}
console.log(setB.difference(setA)); // Set(0) {}

 

아래와 같이 구현 가능하다.

 

Set.prototpe.difference = function (set) {
	return new Set([...this].filter(v => !set.has(v)));
};

 

 

부분 집합과 상위 집합

 

A가 B에 포함되는 경우 A는 B의 부분 집합이며, B는 A의 상위 집합이다.

 

 

Set.prototype.isSuperset = function (subset) {
	for (const value of subset) {
    	if (!this.has(value)) return false;
    }
    
    return true;
}

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

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

 

아래와 같이 구현할수도 있다.

 

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

 

 

728x90
반응형