[JavaScript] Set 자료형

최윤석·2023년 1월 26일
1

JavaScript

목록 보기
1/2

Set 자료형

  • 교유한 값의 모음
  • 각각의 값은 Set안에서 한번만 나타날 수 있다.
  • 모든 데이터 유형의 값을 받을 수 있다.

Set Methods

MethodDescription
new Set()Set을 생성한다.
add()Set에 새로운 원소를 추가한다.
delete()Set에서 원소를 제거한다.
has()만약 원소가 있다면 true를 반환한다.
clear()Set안의 모든 원소를 제거한다.
forEach()각 요소에 대해 callback 함수를 호출한다.
values()Set의 모든 값을 포함하는 Iterator를 반환한다.
keys()values()와 동일하다.
entries()Set에서 [value,value] 쌍을 가진 Iterator를 반환한다.

PropertyDescription
sizeSet의 요소 수를 반환한다.

Array 객체와의 관계

var myArray = ['value1', 'value2', 'value3'];

// Array를 Set으로 변환하기 위해서는 정규 Set 생성자 사용
var mySet = new Set(myArray);

mySet.has('value1'); // true 반환

// set을 Array로 변환하기 위해 전개 연산자 사용함.
console.log([...mySet]); // myArray와 정확히 같은 배열을 보여줌

기본 집합 연산 구현

// 상위집합인지 판단
Set.prototype.isSuperset = function(subset) {
    for (var elem of subset) {
        if (!this.has(elem)) {
            return false;
        }
    }
    return true;
}
// 합집합 구하기
Set.prototype.union = function(setB) {
    var union = new Set(this);
    for (var elem of setB) {
        union.add(elem);
    }
    return union;
}
// 교집합 구하기
Set.prototype.intersection = function(setB) {
    var intersection = new Set();
    for (var elem of setB) {
        if (this.has(elem)) {
            intersection.add(elem);
        }
    }
    return intersection;
}
// 차집합 구하기
Set.prototype.difference = function(setB) {
    var difference = new Set(this);
    for (var elem of setB) {
        difference.delete(elem);
    }
    return difference;
}

//Examples
var setA = new Set([1, 2, 3, 4]),
    setB = new Set([2, 3]),
    setC = new Set([3, 4, 5, 6]);

setA.isSuperset(setB); // => true
setA.union(setC); // => Set [1, 2, 3, 4, 5, 6]
setA.intersection(setC); // => Set [3, 4]
setA.difference(setC); // => Set [1, 2]

Array vs Set

요소를 추가하는 경우

const n = 100000;
const myArr = Array.from(Array(n)).map((v, i) => i);
const mySet = new Set(myArr);

console.time("push array");
myArr.push(n + 1);
console.timeEnd("push array");

console.time("add set");
mySet.add(n + 1);
console.timeEnd("add set");

// n = 100,000
// push array: 0.563232421875 ms
// add set: 0.004150390625 ms

// n = 1,000,000
// push array: 2.4091796875 ms
// add set: 0.001953125 ms

요소를 제거하는 경우

console.time("indexOf, splice array");
const index = myArr.indexOf(n / 2);
myArr.splice(index, 1);
console.timeEnd("indexOf, splice array");

console.time("delete loop set");
mySet.delete(n / 2);
console.timeEnd("delete loop set");

// n = 100,000
// indexOf, splice array: 0.034912109375 ms
// delete loop set: 0.002685546875 ms

// n = 1,000,000
// indexOf, splice array: 0.386962890625 ms
// delete loop set: 0.001953125 ms

요소를 탐색하는 경우

console.time("indexOf array");
myArr.indexOf(n / 2);
console.timeEnd("indexOf array");

console.time("has set");
mySet.has(n / 2);
console.timeEnd("has set");

// n = 100,000
// indexOf array: 0.01318359375 ms
// has set: 0.001220703125 ms

// n = 1,000,000
// indexOf array: 0.130126953125 ms
// has set: 0.0009765625 ms

요소를 순회하는 경우

const length = myArr.length

console.time("for loop array");
for (let i = 0; i < length; i++) {
    myArr;
}
console.timeEnd("for loop array");

console.time("forEach loop array");
myArr.forEach((v) => {
    myArr;
});
console.timeEnd("forEach loop array");

console.time("for of loop array");
for (let i of myArr) {
    myArr;
}
console.timeEnd("for of loop array");

console.time("forEach loop set");
mySet.forEach((v) => {
    mySet;
});
console.timeEnd("forEach loop set");

console.time("for of loop set");
for (let v of mySet) {
    mySet;
}
console.timeEnd("for of loop set");

// n = 100,000
// for loop array: 0.967041015625 ms
// forEach loop array: 1.05078125 ms
// for of loop array: 2.44677734375 ms
// forEach loop set: 0.80224609375 ms
// for of loop set: 1.56396484375 ms

// n = 1,000,000
// for loop array: 1.55126953125 ms
// forEach loop array: 6.134033203125 ms
// for of loop array: 9.910888671875 ms
// forEach loop set: 6.044921875 ms
// for of loop set: 9.925048828125 ms
NArraySet
요소를 추가하는 경우 (push/add)100,0000.563 ms0.004 ms
 1,000,0002.409 ms0.002 ms
요소를 제거하는 경우 (inexOf , splice / delete)100,0000.0349 ms0.002 ms
 1,000,0000.387 ms0.002 ms
요소를 탐색하는 경우 (indexOf/has)100,0000.013 ms0.001 ms
 1,000,0000.130 ms0.001 ms
요소를 순회하는 경우 (for) 100,0000.967 ms 
 1,000,0001.551 ms 
요소를 순회하는 경우 (forEach) 100,0001.05 ms0.802 ms
 1,000,0006.134 ms6.045 ms
요소를 순회하는 경우 (for ... of) 100,0002.446 ms1.563 ms
 1,000,0009.910 ms9.925 ms

결과

  • 요소를 추가, 제거, 탐색하는 경우 Set이 더 빠르며 N이 커질수록 확연한 차이를 볼 수 있다.
    하지만, 이러한 작업을 위해 ArraySet으로 변환하여 작업하는 것은 변환 시간이 오래 걸릴 수 있으므로 주의가 필요하다.
  • 요소를 순회하는 경우 forEach, for ... of 모두 SetArray의 차이가 거의 나지 않는 것을 볼 수 있다.
    하지만 Array의 경우 for을 사용한 순회가 다른 방법에 비해 훨씬 빠른 성능을 보인다.
    따라서 Array의 경우 성능이 중요한 경우 for을 사용하여 순회하자.
    단, for을 사용한 순회시 forEach에 비해 가독성이 떨어질 수 있으므로 주의하자.

참고
Set | MDN
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Set
JavaScript Sets
https://www.w3schools.com/js/js_object_sets.asp
Javascript Set vs. Array performance
https://stackoverflow.com/questions/39007637/javascript-set-vs-array-performance
for loopforEach보다 빠른 이유
https://stackoverflow.com/questions/43821759/why-array-foreach-is-slower-than-for-loop-in-javascript

profile
프론트엔드를 공부하고 있는 주니어 개발자입니다.

0개의 댓글