모던 자바스크립트 Deep Dive (Set, Map정리)

Minju Kang·2023년 8월 17일
1

Set과 Map

Set

Set객체와 배열의 차이

  • Set객체의 특성은 수학적 집합의 특성과 일치
  • Set은 수학적 집합을 구현하기 위한 자료구조
  • Set을 통해 교집합, 합집합, 차집합, 여집합 등을 구현 가능

중복된 요소 제거 방법

//배열의 중복 요소 제거
const uniq = arr => arr.filter((v,i,self) => self.indexOf(v) === i);

//Set을 사용한 배열의 중복 요소 제거
const uniq = array => [...new Set(array)];

Size

요소 개수 확인

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

add

요소 추가

Set 객체에 중복된 요소의 추가는 허용되지 않는다. 에러는 발생하지 않음

const set = new Set();
set.add(1).add(2);  //Set(2) {1,2}

has

요소 존재 여부 확인

특정 요소의 존재 여부를 나타내는 불리언 값을 반환

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

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

delete

요소 삭제

삭제 성공여부를 나타내는 불리언 값을 반환

인덱스가 아니라 삭제하려는 요소값을 인수로 전달해야 함

Set 객체는 순서에 의미가 없어 인덱스를 찾지 않음

존재하지 않는 요소를 삭제하려고 하면 에러 없이 무시

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

set.delete(0);
console.log(set);  //set(1) {3}
//add메서드와 달리 연속적으로 호출할 수 없다.
set.delete(1).delete(2);  //TypeError: set.delete(...).delete is not a function

clear

요소 일괄 삭제

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

const set = new Set([1,2,3]);
set.clear();
console.log(set); // Set(0) {}

forEach

배열에서의 forEach 메서드와 유사하게 콜백 함수와 forEach 메서드의 콜백 함수 내부에서 this로 사용될 객체를 인수로 전달

콜백 함수는 다음과 같이 3개의 인수를 전달

  • 첫 번째 인수 : 현재 순회 중인 요소값
  • 두 번째 인수 : 현재 순회 중인 요소값
  • 세 번째 인수 : 현재 순회 중인 Set 객체 자체

Set 객체는 순서에 의미가 없어 배열과 같이 인덱스를 갖지 않음

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

set.forEach((v, v2, set)=> console.log(v, v2, set));
/*
1 1 Set(3) {1, 2, 3}
2 2 Set(3) {1, 2, 3}
3 3 Set(3) {1, 2, 3}
*/

Set 객체는 이터러블

이터러블

  • 반복할 수 있다는 의미를 갖고 있음
  • 메서드 Symbol.iterator가 구현된 객체를 의미
  • 이터러블한 것은 for … of 반복문 사용 가능
  • 스프레드 문법과 배열 디스트럭처링의 대상이 될 수도 있음
const set = new Set([1,2,3]);
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]

집합 연산

교집합

//교집합 함수
//방법1
Set.prototype.intersection = function (set) {
	const result = new Set();
	
	for(const value of set){
		if(this.has(value) result.add(value);
	}
	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]);

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

합집합

//방법1
Set.prototype.union = function (set){
	const result = new Set(this);

	for(const value of set){
		result.add(value);
	}
	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([2, 4]);

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

차집합

//방법1
Set.prototype.difference = function (set){
	const result = new Set(this);
	
	for(const value of set){
		result.delete(value);
	}
	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) {}

부분 집합과 상위 집합

//방법1
Set.prototype.isSuperset = function (subset){
	for(const value of subset){
		if(!this.has(value)) 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 setB = new Set([2, 4]);

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

Map

Map과 객체의 차이

Map 객체의 생성

const map = new May();
console.log(map);  // Map(0) {}

Map 생성자 함수는 이터러블을 인수로 전달받아 Map 객체를 생성.

인수로 전달되는 이터러블은 키와 값의 쌍으로 이루어진 요소로 구성되어야 함.

const map1 = new Map([['key1', 'value1'], ['key2','value2']]);
console.log(map1); // Map(2) {"key1" => "value1", "key2" => "value2"}

const map2 = new Map([1, 2]); // TypeError : Iterator value 1 is not an entry object

Map 생성자 함수의 인수로 전달한 이터러블에 중복된 키를 갖는 요소가 존재하면 값이 덮어써짐

const map = new Map([['key1', 'value1'], ['key1', 'value2']]);
console.log(map); // Map(1) {'key1' => 'value2'}

size

요소 개수 확인

const { size } = new map([['key1', 'value1'], ['key2', 'value2']]);
console.log(size);  // 2

set

요소 추가

set 메서드를 연속적으로 호출할 수 있다.

중복된 키를 갖는 요소를 추가하면 값이 덮어 써진다.

const map = new Map();
console.log(map);  // Map(0) {}

map.set('key1', 'value1');
console.log(map); // Map(1) {'key1' => 'value1'}

map.set('key2', 'value2').set('key3', 'value3');
console.log(map); // Map(3) {'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3'}

객체는 문자열 또는 심벌 값만 키로 사용할 수 있지만 Map객체는 키 타입에 제한이 없음

객체를 포함한 모든 값을 키로 사용할 수 있음

const map = new Map();

const lee = { name: 'Lee' };
const kim = { name: 'Kim' };

map.set(lee, 'developer').set(kim, 'designer');
console.log(map);
//Map(2) { {name: 'Lee'} => 'developer', {name: 'Kim'} => 'designer' }

get

요소 취득

get 메서드의 인수로 키를 전달하면 Map 객체에서 인수로 전달한 키를 갖는 값을 반환

키를 갖는 요소가 존재하지 않으면 undefined를 반환함.

const map = new Map();

const lee = { name: 'Lee'};
const kim = { name: 'Kim'};

map.set(lee, 'developer').set(kim, 'designer');
console.log(map.get(lee)); //developer
console.log(map.get('key')); //undefined

has

요소 존재 여부 확인

특정 요소의 존재 여부를 나타내는 불리언 값을 반환

delete

요소 삭제

삭제 성공 여부를 나타내는 불리언 값을 반환

존재하지 않는 키로 Map 객체의 요소를 삭제하려 하면 에러 없이 무시됨

delete 메서드는 set 메서드와 다르게 연속적으로 호출 할 수 없다.

clear

요소 일괄 삭제

초기화 시킴

forEach

요소 순회

콜백 함수는 3개의 인수를 전달

  • 첫 번째 인수 : 현재 순회 중인 요소값
  • 두 번째 인수 : 현재 순회 중인 요소키
  • 세 번째 인수 : 현재 순회 중인 Map 객체 자체
const lee = {name : 'Lee'};
const kim = {name : 'Kim'};

const map = new Map([[lee, 'developer'], [kim, 'designer']]);

map.forEach((v,k,map) => console.log(v, k, map));
/*
developer { name: "Lee" } Map(2) {
	{name: "Lee"} => "developer",
	{name: "Kim"} => "designer"
}
designer { name: "KIm" } Map(2) {
	{name: "Lee"} => "developer",
	{name: "Kim"} => "designer"
}
*/

Map 객체는 이터러블이다. 스프레드 문법과 배열 디스트럭처링 할당의 대상이 될 수도 있다.

Map 객체는 이터레이터인 객체를 반환하는 메서드를 제공

const lee = { name: 'Lee' };
const kim = { name: 'Kim' };

const map = new Map([[lee, 'developer'], [kim, 'designer']]);

for ( const key of map.keys()){
	console.log(key);  // {name : "Lee"} {name: "Kim"}
}

for ( const value of map.values()) {
	console.log(value);  // developer designer
}

for ( const entry of map.entries()) {
	console.log(entry);  // [{name: "Lee"}, "developer"] [{name: "Kim"}, "designer"]
}
profile
나의 기억저장소

1개의 댓글

comment-user-thumbnail
2023년 8월 17일

좋은 정보 감사합니다

답글 달기