Set | 집합

Set(집합)은 정렬되지 않은 컬렉션으로 중복된 원소가 없다.

집합은 유일하게 구분되는 원소의 모임이다.

집합 만들기

function Set() {
var items = {};
}

배열이 아닌 객체로 집합을 표현한다.

자바스크립트 객체는 동일한 키로 여러 프로퍼티를 가질 수는 없으므로 집합에서 원소가 중복되지 않는 특성이 그대로 보장된다.

다음은 Set 클래스에서 구현할 메서드이다.

add() : 원소를 추가한다. remove() : 원소를 삭제한다. has() : 어떤 원소가 집합에 포함되어 있는지 여부를 true/false로 반환한다. clear() : 모든 원소를 삭제 size() : 원소의 개수를 반환 values() : 집합의 모든 원소를 배열 형태로 반환

has 메서드

this.has = function(value) {
return value in items;
};

집합의 모든 원소는 객체에 담겨 있으므로 자바스크립트 in 연산자로 해당 원소가 items 프로퍼티 중 하나인지 확인한다.

아니면

this.has = function(value) {
return items.hasOwnProperty(value);
};

자바스크립트 객체는 hasOwnProperty 메서드를 상속하는 것을 응용한 것이다. 객체가 어떤 프로퍼티를 갖고 있는지 여부를 조사한다.

add 메서드

새 원소를 추가하는 것이다.

this.add = function(value) {
if (!this.has(value)) {
items[value] = value;
return true;
}
return false;
};

value가 이미 집합에 포함되어 있는지 먼저 확인한다 없는 원소라면 value를 넣고 true를 반환, 있는 원소라면 false를 반환해서 추가 여부에 대한 표시를 한다.

remove와 clear 메서드

this.remove = function(value) {
if (this.has(value)) {
delete items[value];
return true;
}
return false;
};

삭제할 원소가 집합에 존재하는지 먼저 확인하고 있는 원소라면 원소를 삭제하고 true를 반환한다. 그외는 false를 한다.

삭제할때는 간단하게 delete 연산자로 items에서 해당 프로퍼티를 지운다.

this.clear = function() {
items = {};
};

집합의 모든 원소를 날릴때는 빈 객체를 할당하면 된다.

size 메서드

size를 구하는 방법은 3가지가 있다.

LinkedList 처럼 add,remove 호출할때 마다 값을 바꿔주는 방법

Object 클래스에 내장된 함수를 이용 하는 방법

this.size = function() {
return Object.keys(items).length;
};

Object.keys는 객체의 모든 프로퍼티를 배열로 변환한다. 따라서 배열의 length로 원소 개수를 파악할 수 있다.

하지만 비교적 최신 브라우저에서만 제대로 작동한다.

셋째 items의 프로퍼티가 모두 몇 개 인지 세어본다.

this.sizeLegacy = function() {
var count = 0;
for (var prop in items) {
if (items.hasOwnProperty(prop)) {
++count;
}
}
return count;
};

items 객체의 프로퍼티를 루프로 순회하면서 유효한지 체크한다. 유효한 프로퍼티라면 count 변수 값을 증가 시키고 마지막에 반환한다.

value 메서드

같은 방법으로 items의 모든 프로퍼티를 추출해 배열 형태로 반환한다.

this.value = function() {
return Object.keys(items);
};

위의 코드는 비교적 최신 브라우저에서만 작동한다.

this.valueLegacy = function() {
var keys = [];
for (var key in items) {
if (items.hasOwnProperty(key)) {
keys.push(key);
}
}
return keys;
};

집합 연산

집합에서 사용 가능한 연산은 네가지가 있다.

합집합: 두 집합 중 어느 한쪽이라도 포함된 원소로 구성된 집합을 구한다.

교집합: 두 집합 모두 포함되어 있는 원소로 구성된 집합을 구한다.

차집합: 첫 번쨰 집합에는 있지만 두 번째 집합에는 없는 원소로 구성된 집합을 구한다.

부분집합: 어떤 집합이 다른 집합의 일부인지 확인한다.

합집합

A, B 어느 한쪽에 속하는 원소 x의 집합니다.

this.union = function(otherSet) {
var unionSet = new Set();
var values = this.values();
for (var i = 0; i < values.length; i++) {
unionSet.add(values[i]);
}
values = otherSet.values();
for (var i = 0; i < values.length; i++) {
unionSet.add(values[i]);
}
return unionSet;
};

먼저 합집합 unionSet을 생성한다. 첫 번쨰 집합의 values 메서드로 모든 원소를 추출한뒤 루프로 반복하면서 unionSet에 추가한다

같은 로직을 두번쨰 집합에도 적용한 후 unionSet을 반환한다.

교집합

A에도 속하고 B에도 속하는 원소 x의 집합이다.

this.intersection = function(otherSet) {
var intersectionSet = new Set();
var values = this.values();
for (var i = 0; i < values.length; i++) {
if (otherSet.has(values[i])) {
intersection.add(values[i]);
}
}
return intersection;
};

차집합

A에는 속하지만 B에는 속하지 않는 원소 x의 집합이다.

this.difference = function(otherSet) {
var differenceSet = new Set();
var values = this.values();
for (var i = 0; i < values.length; i++) {
if (!otherSet.has(values[i])) {
differenceSet.add(values[i]);
}
}
return differenceSet;
};

부분집합

A의 모든 원소는 반드시 B에 존재함을 의미한다.

this.subset = function(otherSet) {
if (this.size() > otherSet.size()) {
return false;
} else {
var values = this.values();
for (var i = 0; i < values.length; i++) {
if (!otherSet.has(values[i])) {
return false;
}
}
return true;
}
};

가장 먼저 현재 인스턴스(this)의 크기를 확인한다. this가 otherSet보다 원소가 많다면 이미 부분집합 조건이 맞지 않는다.

부분집합은 비교 대상 집합보다 원소 개수가 같거나 적어야 한다.

그 다음은 원소를 순회하면서 각 원소가 otherSet에 존재하는지 확읺나다.

하나라도 otherSet에 존재하지 않으면 부분집합이 아니므로 바로 false를 반환한다.

루프를 정상 종료했다면 this의 모든 원소가 otherSet에도 있다는 뜻으로 true를 반환한다.