set
은 자주 사용해서 어느정도 익숙한 편인데, map
은 좀처럼 사용해지질 않아서 익숙하지가 않다. 그래서 map
을 다시 공부할겸 set
도 같이 정리하려고 한다.
중복을 허용하지 않는 유일한 값들의 집합.
교집합
, 합집합
, 차집합
, 여집합
등 구현 ⭕️set
객체 생성const set = new Set();
console.log(set); // Set(0){}
set
객체는 set
생성자를 사용해서 집합을 생성할 수 있다.const set1 = new Set([1, 2, 3]);
console.log(set1); // Set(3){1, 2, 3}
const set2 = new Set('123');
console.log(set2); //Set(3) { '1', '2', '3' }
set
생성자 함수는 인수로 iterable(배열, 맵, 집합, 문자열)을 받는다. 삽입
const set2 = new Set([1, 2, 3]);
set2.add(4); // Set(4) { 1, 2, 3, 4 }
add()
메소드를 통해 삽입할 수 있다. 삭제
const set3 = new Set([1, 2, 3, 4]);
set3.delete(4); // Set(3) { 1, 2, 3 }
delete()
메소드를 통해 삭제할 수 있다. 일괄 삭제
const set3 = new Set([1, 2, 3, 4]);
set3.clear();
console.log(set3); // Set(0){}
포함여부
확인const set4 = new Set([1, 2, 3]);
console.log(set4.has(3)); // true
console.log(set4.has(6)); // false
has()
메소드를 통해 포함 여부를 확인할 수 있는데 결과 값은 true
/false
로 나온다 중복요소 제거
const set5 = array => [...new Set(array)];
console.log(set5([1, 1, 2, 2, 2, 3, 3, 3, 3])) // [ 1, 2, 3 ]
set
객체는 중복된 값을 저장하지 않기 때문에 위의 예시처럼 추가해도 중복된 값은 추가되지 않는다. 요소 순회
const set6 = 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
객체의 요소를 순회하기 위해선 Set.prototype.forEach
를 사용해야한다. Array.prototype.forEach
메서드와 유사하게 콜백함수
와 forEach
메서드의 콜백함수 내부에서 this
로 사용할 객체를 전달할 3가지 객체를 인수로 전달한다. 현재 순회중인 요소값
, 현재 순회중인 요소 값
, 현재 순회중인 set객체 자체
1
, 2
번째 인수가 같은 이유 : Array.prototype.forEach
메서드와 인터페이스를 통일하게 하기 위해서다. Set.prototype.intersection = function(set){
return new Set([...this].filter(v=>set.has(v)));
}
const set7 = new Set([1, 2, 3, 4, 5]);
const set8 = new Set([2, 5]);
// set7과 set8의 교집합
console.log(set7.intersection(set8)); // Set(2) {2, 5}
// set8과 set7의 교집합
console.log(set8.intersection(set7)); // Set(2) {2, 5}
this
는 메서드를 호출한 객체다....
spread 문법으로 새로운 집합을 만든 뒤, filter
를 통해서 set.has()
와함께 나머지 집합들이 해당 원소를 가졌는지 체크해준다. Set.prototype.union = function (set) {
return new Set([...this, ...set]);
};
const set9 = new Set([1, 2, 3, 4, 5]);
const set10 = new Set([2, 5]);
// set9과 set10의 합집합
console.log(set9.union(set10)); // Set(5) {1, 2, 3, 4, 5}
// set10과 set9의 합집합
console.log(set10.union(set9)); // Set(5) { 2, 5, 1, 3, 4 }
...
spread 문법을 통해 두 set를 합쳐서 새로운 set를 리턴한다.Set.prototype.difference = function (set) {
return new Set([...this].filter(v => !set.has(v)));
};
const set11 = new Set([1, 2, 3, 4, 5]);
const set12 = new Set([2, 5]);
// set11에 대한 set12의 차집합
console.log(set11.difference(set12)); // Set(3) { 1, 3, 4 } -> set12가 안가지고 있는것만 출력
// set12에 대한 set11의 차집합
console.log(set12.difference(set11));// Set(0) {} // set11이 안가지고 있는 것만 출력 => 다 가지고 있으니 {}
위와 동일
function differenceSet(set11, set12){
let difference = new Set(set11)
set12.forEach(e => {
difference.delete(e)
})
return difference
}
let set11 = new Set([1, 2, 3]);
let set12 = new Set([3, 4, 5]);
console.log(differenceSet(set11, set12)); // Set(2) {1, 2}
console.log(differenceSet(set12, set11)); // Set(2) {4, 5}
차집합
의 경우 순서
에따라 경과가 다르기때문에 순서에 신경을 써야한다. Set.prototype.isSuperset = function (subset) {
const supersetArr = [...this];
return [...subset].every(v => superSetArr.includes(v));
};
cosnt set13 = new Set([1, 2, 3, 4, 5]);
const set14 = new Set([2, 5]);
// set13이 set14의 상위 집합인가
console.log(set13.isSuperset(set14)); // true
// set14가 set13의 상위 집합인가
console.log(set14.isSuperset(set13)); // false
this
는 subset
의 상위 집합인지 확인한다.every
를 이용하여 모든 [...subset]의 요소들이 superSetArr에 존재하는지 확인한 뒤, true/false 반환 차집합
의 경우 순서
에따라 경과가 다르기때문에 순서에 신경을 써야한다. add(value)
: 값을 추가 & set 반환
delete(value)
: 값을 제거
has(value)
: set 내에 값 존재하면 = true
, 없으면 = false
반환
clear()
: set 안의 모든 값 제거
size
: set이 가지고 있는 값 개수.
주로 `for`문 돌릴 때 배열의 경우
`for(let i = 0; i<arr.length; i++)` 이렇게 돌렸는데,
`set`으로 돌릴려면 `for(let i=0; i < set.size; i++)`이렇게 돌렸다.
Map이란 Key-Value 형태의 집합 데이터.
key가 있는 데이터를 저장하고 있기 때문에 객체와 유사하다.
다만, map
은 key에 다양한 자료형을 허용, 삽입된 순서를 기억하고 있다.
map()
은 callbackFunction
을 실행한 결과를 가지고 새로운 배열을 만들 때 사용한다.
array.map(callbackFunction(currenValue, index, array), thisArg)
callbackFunction
, thisArg
두 개의 매개변수가 있다.
callbackFunction : currentValue, index, array 3개의 매개변수를 갖는다
currentValue : 배열 내 현재 값
index : 배열 내 현재 값의 인덱스
array : 현재 배열
thisArg : callbackFunction 내에서 this로 사용될 값
const emotions = ["happy", "sad", "blue"];
map을 이용하면, 배열의 요소를 하나 하나씩 출력할 수 있다.
const emotions = ["happy", "sad", "blue"];
const face = emotions.map(emotion=>console.log(emotion));
// happy
// sad
// blue
그렇기 때문에 각 요소에다 다른 값을 추가할 수도 있다.
const emotions = ["happy", "sad", "blue"];
const face = emotions.map(emotion => console.log(`😊 ${emotion}`));
// 😊 happy
// 😊 sad
// 😊 blue
아래처럼 더 간결하게 표현할 수 있다.
const emotions = ["happy", "sad", "blue"];
const addFace = emotion => `😊 ${emotion}`;
const emotionsWithFace = emotions.map(addFace);
console.log(emotionsWithFace);
// (3) ['😊 happy', '😊 sad', '😊 blue']
index가 뭔지도 알아낼 수 있다.
const emotions = ["happy", "sad", "blue"];
const indexWithEmotions = emotions.map((emotion, index)=> `${index} => ${emotion}`);
console.log(indexWithEmotions);
// ['0 => happy', '1 => sad', '2 => blue']
여기서, map((1, 2)=>)
의 1번째는 배열의 각 요소를 말하며, 2번째 요소는 index값이다.
let numbers = [2, 4, 6, 8, 10];
let addResults = numbers.map(number => number + 1);
console.log(addResults);
// (5) [3, 5, 7, 9, 11]
let profiles = [
{studentId: '01A', name: "Olivia"},
{studentId: '02B', name: "Violet"},
{studentId: '03C', name: "ViVian"}
]
let getStudentId = profiles.map(profile => profile.studentId);
console.log(getStudentId);
// (3) ['01A', '02B', '03C']
let getStudentName = profiles.map(profile => profile.name);
console.log(getStudentName);
// (3) ['Olivia', 'Violet', 'ViVian']
let profiles = [
{studentId: '01A', name: "Olivia"},
{studentId: '02B', name: "Violet"},
{studentId: '03C', name: "ViVian"}
]
let getStudentName = profiles.map(profile => profile.name);
console.log(getStudentName[1]);
// Violet
let numbers = [1, 3, 5, 7, 9];
let reverseNumbers = numbers.reverse().map(number=>number);
console.log(reverseNumbers);
// [9, 7, 5, 3, 1]
revers
를 통해 배열을 뒤집을 수 있다.
그러나 이렇게만 처리하면 원본 배열 값도 바뀐다.
원본 값은 바뀌지 말아야하기 때문에 slice
를 통해 배열을 복사한 뒤 처리하는 것이 좋다.
const numbers = [1, 3, 5, 7, 9];
const reverseNumbersWithSlice = numbers.slice(0).reverse().map(number => number);
console.log(reverseNumberWithSlice);
// (5) [9, 7, 5, 3, 1]
console.log(numbers);
// (5) [1, 3, 5, 7, 9]
배열 값을 잘라서 새로운 배열로 return해준다.
arr.slice(begin, end)
let fruits = ["apple", "grape", "melon", "orange", "banana"];
let favFruits = fruits.slice(1,2);
console.log(favFruits);
// (2) ['grape', 'melon']
console.log(frutis);
// (5) ['apple', 'grape', 'melon', 'orange', 'banana']
역시 원본 배열값은 살아있다.
여기서 end 처리를 하지 않는다면 begin부터 배열 끝까지 새로운 배열로 return해준다.
let fruits = ["apple", "grape", "melon", "orange", "banana"];
let favFruits = fruits.slice(1);
console.log(favFruits);
// (4) ['grape', 'melon', "orange", "banana"]
let levels = [["L1", "L2", "L3"], ["L4", "L5", "L6"], ["L7", "L8", "9"]];
let reverseLevel = levels.map(level => level.slice(0).reverse().map(lev=>lev));
console.log(reverseLevel);
// 0: (3) ['L3', 'L2', 'L1']
// 1: (3) ['L6', 'L5', 'L4']
// 2: (3) ['9', 'L8', 'L7']
let levels = [["L1", "L2", "L3"], ["L4", "L5", "L6"], ["L7", "L8", "9"]];
let reverseLevel = levels.slice(0).reverse().map(level => level.map(lev => lev));
console.log(reverseLevel);
// 0: (3) ['L7', 'L8', '9']
// 1: (3) ['L4', 'L5', 'L6']
// 2: (3) ['L1', 'L2', 'L3']
let recipe = new Map([['tomatos', 2], ['onion', 1], ['paper', 0.5]]);
for (const ingredient of recipe.keys()){
console.log(ingredient);
}
// tomatos, onion, paper
let recipe = new Map([['tomatos', 2], ['onion', 1], ['paper', 0.5]]);
for(const amount of recipe.values()){
console.log(amount);
}
// 2, 1, 0.5
let recipe = new Map([['tomatos', 2], ['onion', 1], ['paper', 0.5]]);
for(const whatINeed of recipe){
console.log(whatINeed);
}
// (2) ['tomatos', 2]
// (2) ['onion', 1]
// (2) ['paper', 0.5]
set(key, value)
: key를 이용하여 value를 저장
get(key)
: key에 해당하는 값을 반환. & key가 ❌면 undefined
반환
delete(key)
: key 값 삭제
has(key)
: key가 존재하면 true, 아니면 false
size
: map 요소 개수
👩🏻💻 참고 자료
https://www.w3schools.com/js/js_sets.asp
https://www.w3schools.com/js/js_maps.asp
https://ko.javascript.info/map-set