프로젝트를 진행하거나 실무에서 Set
과 Map
을 유용하다고 생각해본적이 없는 것 같다. 항상 언제 쓰는지 궁금증이 있었는데 개념을 공부해보고 유즈케이스에 대해서도 알아보려 한다.
먼저 Set에 대해서 알아보자.
자바스크립트의 데이터타입은 크게 두 가지로 나뉘어진다.
크게 원시타입과 객체타입으로 나뉘어지는데 숫자, 문자열, null, undefined, boolean, symbol을 제외한 모든 타입은 객체 타입이다. 따라서 Set도 마찬가지로 객체라고 할 수 있다
일반 객체와 무엇인가 다르기 때문에 나누어두었다고 생각이 든다.
Set
객체는 중복되지 않는 유일한 값들의 집합이다. 배열과 유사하지만 다음의 차이를 가진다.
Set 객체는 생성자 함수로 생성한다.
const set = new Set();
console.log(set); // Set(0) {}
Set 생성자 함수는 이터러블을 인수로 전달받아 Set 객체를 생성한다. 이 때 이터러블의 중복된 값은 Set 객체에 요소로 저장되지 않는다
const sampleSet = new Set([1,2,3,4,4]);
console.log(sampleSet); // Set(3) {1,2,3,4}
const sampleSet2 = new Set('hello');
console.log(sampleSet2); // Set(4) {"h", "e", "l", "o"}
이러한 특성 때문에 알고리즘을 공부할 때 Set을 이용해서 간단하게 배열의 중복을 제거하기도 한다 👍
const filtered = [...new Set([1,2,2,2,3])];
console.log(filtered); // [1, 2, 3];
Set 객체의 요소 개수를 확인할 때는 Set.prototype.size
를 사용한다.
const newSet = new Set([1, 2, 3, 4, 5, 5]);
console.log(newSet.size); // 5
size
프로퍼티는 setter
가 없이 getter
만 존재하는 접근자이다. 따라서 할당으로 값을 변경할 수 없다.
요소를 추가할 때는 Set.prototype.add
를 사용한다.
const newSet = new Set();
console.log(newSet); // Set(0) {}
newSet.add(1).add(2).add(3);
console.log(newSet); // Set(3) {1, 2, 3}
add
메서드는 새로운 요소가 추가된 Set
객체를 반환한다. 따라서 add 메서드 이후에 체이닝해서 사용할 수 있다.
Set 객체는 일반 객체와 배열과 같이 js의 모든 값을 추가할 수 있다
const newSet = new Set();
newSet
.add(1)
.add('h')
.add(true)
.add(undefined)
.add(null)
.add([])
.add(function hello() {})
.add({});
console.log(newSet);
// Set(8) { 1, 'h', true, undefined, null, [], [Function: hello], {} }
Set.prototype.has
메서드를 사용한다.
const newSet = new Set([1,2,3]);
console.log(newSet.has(3)); // true
Set.prototype.delete
메서드를 사용한다.
const newSet = new Set([1,2,3]);
newSet.delete(2);
console.log(newSet); // Set(2) {1,3}
Set.prototype.clear
를 하면 모든 요소를 제거할 수 있다.
cosnt newSet = new Set([1,2,3]);
newSet.clear();
console.log(newSet); // Set(0) {}
Set
객체를 순회할 수 있는데 Set.prototype.forEach
메서드를 사용할 수 있다.
3개의 인수를 전달 받는다.
1. 현재 순회 중인 요소값
2. 현재 순회 중인 요소값
3. 현재 순회 중인 Set 객체 자체
1번 인수와 2번째 인수는 같다.
const newSet = new Set([1, 2, 3]);
newSet.forEach((v, v2, set) => console.log(v, v2, set));
Set
은 이터러블이기 때문에 for of
문을 사용할 수 있고 스프레드와 디스트럭처링 또한 가능하다.
const newSet = new Set([1, 2, 3]);
for (const value of newSet) {
console.log(value);
}
console.log([...newSet]);
const [a, ...rest] = newSet;
console.log(a, rest);
// 1
// 2
// 3
// [ 1, 2, 3 ]
// 1 [ 2, 3 ]
Set 객체는 수학적 집합을 구현하기 위한 자료구조이다. 교집합, 합집합, 차집합등을 구현할 수 있다.
다음과 같이 흉내 내볼 수 있다.
Set.prototype.intersection = function (set) {
const result = new Set();
for (const val of set) {
if (this.has(val)) result.add(val);
}
return result;
};
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 4]);
console.log(setA.intersection(setB)); // Set(2) {2,4}
Set.prototype.union = function (set) {
const result = new Set(this);
for (const value of set) {
result.add(value);
}
return result;
};
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([5, 6, 7, 8]);
console.log(setA.union(setB));
// Set(8){1,2,3,4,5,6,7,8}
Set.prototype.difference = function (set) {
const result = new Set(this);
for (const val of set) {
if (this.has(val)) result.delete(val);
}
return result;
};
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 4]);
console.log(setA.difference(setB));
// Set (2) {1,3}
Map
또한 객체이다. Map
은 키와 값의 쌍으로 이루어진 컬렉션이다. 객체와 유사하지만 다음의 차이를 가진다.
Map 객체는 Map 생성자 함수로 생성한다.
const map = new Map();
console.log(map); // Map(0) {}
Map 생성자 함수는 이터러블을 인수로 전달받아 Map객체를 생성한다. 이 때 인수로 전달되는 이터러블은 키와 값의 쌍으로 이루어진 요소로 구성어야 함
const map = new Map([
['key1', 'value1'],
['key2', 'value2'],
]);
console.log(map); // Map(2) { 'key1' => 'value1', 'key2' => 'value2' }
Map.prototype.size
프로퍼티를 사용한다.
Set
과 같이 getter만 존재한다.
const map = new Map([
['key1', 'value1'],
['key2', 'value2'],
]);
console.log(map.size); // 2
Map.prototype.set
메서드를 사용한다.
const map = new Map();
console.log(map);
map.set('key1', 'value1').set('key2', 'value2');
console.log(map); // Map(2) { 'key1' => 'value1', 'key2' => 'value2' }
map은 키 타입의 제한이 없다
Map.prototype.get
메서들르 사용한다.
const map = new Map();
const leo = { name: 'Leo' };
const kim = { name: 'Kim' };
map.set(leo, 'developer').set(kim, 'designer');
console.log(map.get(leo)); // developer
Map.prototype.has
를 사용한다.
Map.prototype.delete
메서드를 사용한다.
Map.prototype.clear
메서드를 사용한다.
Set
과 마찬가지로 Map.prototype.forEach
메서드를 사용한다.
const leo = { name: 'Leo' };
const kim = { name: 'Kim' };
const map = new Map([
[leo, 'developer'],
[kim, 'designer'],
]);
map.forEach((v, k, map) => console.log(v)); // developer designer
map.forEach((v, k, map) => console.log(k)); // { name: 'Leo' } { name: 'Kim' }
map.forEach((v, k, map) => console.log(map));
/**
* Map(2) {
{ name: 'Leo' } => 'developer',
{ name: 'Kim' } => 'designer'
}
Map(2) {
{ name: 'Leo' } => 'developer',
{ name: 'Kim' } => 'designer'
}
*/
//