Frontend/JS.info 정리

자료구조와 자료형 - Map, Set

Creative_Lee 2022. 2. 14. 00:08

객체는 키가 있는 컬렉션을 저장합니다.

배열은 순서가 있는 컬렉션을 저장합니다.

 

위 2개의 자료구조 만으론 부족해서 Map과 Set이 등장했습니다! 

 


Map

Map은 키가 있는 데이터를 저장한다는 점에서 객체와 유사합니다.

다만 Map은 키에 다양한 자료형을 허용합니다.

 

Map에는 다음과 같은 주요 메서드와 프로퍼티가 있습니다!

 

  • new Map( [iterable] ) - Map을 만듭니다. [key, value] 쌍이 있는 iterable 객체를 선택적으로 넘길 수 있습니다.
  • map.set( key, value ) - key를 이용해 value를 저장하고 map 자신을 리턴합니다.
  • map.get( key ) - key에 해당하는 값을 리턴합니다, key가 존재하지 않으면 undefined를 리턴합니다.
  • map.has( key ) - key의 존재 유무를 Boolean으로 리턴합니다.
  • map.delete( key ) - key에 해당하는 값을 삭제합니다.
  • map.clear( ) - map의 내부 요소를 모두 제거합니다.
  • map.size - map의 요소의 개수를 리턴합니다.

 

let mapTest = new Map();

mapTest.set(1, '숫자형 키')
mapTest.set('1', '문자형 키')
mapTest.set(true, '불리언 키!')

console.log(mapTest.get(1))
console.log(mapTest.get('1'))
console.log(mapTest.get(true))

Map은 key에 다양한 자료형을 허락합니다!
객체와 다르게 key에 숫자, 불리언이 들어와도 문자형으로 형 변환 하지 않습니다.

 

 

Map은 심지어 key로 객체도 허용합니다.

let imObject = {im : 'object'}
let mapKeyTest = new Map();

mapKeyTest.set(imObject, 'Map은 key에 객체까지 허용합니다!')

console.log(mapKeyTest.get(imObject)) // Map은 key에 객체까지 허용합니다!

 

Map은 특정 알고리즘을 사용해 값의 등가 여부를 확인합니다.

이 알고리즘은 일치 연산자 === 와 거의 유사하지만,

NaN과 NaN 을 같다고 취급하는 것에서 일치 연산자와 차이가 있습니다.

 

따라서 Map의 key로 NaN도 사용할 수 있습니다!

 

 


map.set 체이닝

map.set은 호출 시 키에 값을 저장함과 동시에 map 자기 자신을 리턴합니다.

이를 이용해서 map.set 체이닝이 가능합니다!

 

let chainingMap = new Map();

chainingMap.set(1,'1')
           .set(2,'2')
           .set(3,'3')

console.log(chainingMap.get(1)) // 1
console.log(chainingMap.get(2)) // 2
console.log(chainingMap.get(3)) // 3

 

 

 


Map의 요소에 반복 작업하기

  • map.keys( ) - 각 요소의 키를 모은 iterable 객체를 반환합니다.
  • map.values( ) - 각 요소의 값을 모은 iterable 객체를 반환합니다.
  • map.entries( ) - 요소의 [키, 값] 을 한 쌍으로 하는 iterable 객체를 리턴합니다.
                         iterable 객체는 for..of문 의 기초로 쓰입니다.

 

let flowerMap = new Map([
  ['Rose',5000],
  ['Tulip',3000],
  ['Sunflower',4000]
]);

for(let flower of flowerMap.keys()){
  console.log(flower)
}

for(let price of flowerMap.values()){
  console.log(price)
}

for(let entry of flowerMap){
  console.log(entry)
}

 

콘솔창

 

map은 값이 삽입된 순서대로 순회를 실시합니다.

객체가 순서를 보장하지 않는 것과는 다릅니다!

let flowerMap = new Map([
  ['Rose',5000],
  ['Tulip',3000],
  ['Sunflower',4000]
]);

flowerMap.forEach((value,key)=>{
  console.log(`${value} ${key}`)
})
// 5000 Rose
// 3000 Tulip
// 4000 Sunflower

 

 

map에 forEach도 사용 가능합니다.

let flowerMap = new Map([
  ['Rose',5000],
  ['Tulip',3000],
  ['Sunflower',4000]
]);

flowerMap.forEach((value,key,map)=>{
  console.log(`${value} ${key}`)
})
// 5000 Rose
// 3000 Tulip
// 4000 Sunflower

 

 


 

각 요소가 key-value 쌍인 배열이나 iterable 객체를 new Map()의 인자로 전달해 새로운 맵을 만드는 것도 가능합니다.

let flowerMap = new Map([
  ['Rose',5000],
  ['Tulip',3000],
  ['Sunflower',4000]
]);

 

Object.entries( obj ) 

일반 객체의 key-value 쌍을 요소 [key, value]로 가지는 배열을 리턴합니다.
(객체를 [key, value] 쌍의 배열로 바꿔줍니다.)

이 값을 new Map()에 인자로 전달해 Map을 만들 수 있습니다.

let obj = {
  name: 'Lee',
  age: 27
};

let map = new Map(Object.entries(obj))

console.log(map.get('name')) // Lee
console.log(map.get('age')) // 27

 

 

 

Object.fromEntries( Map )

Object.entries와 정확하게 반대입니다.

각 요소가 [key, value] 쌍으로 이루어진 배열이나 iterable객체를 일반 객체로 바꿔 줍니다.

자료가 맵에 저장되어 있는데 제3의 코드에서객체 형태로 자료를 받고 싶을 때 사용하면 되겠습니다

 

let obj = {
  name: 'Lee',
  age: 27
};

let map = new Map(Object.entries(obj))
객체를 key,value 쌍의 배열로 바꾸고 이를 다시 map으로 만들었습니다.

let obj2 = Object.fromEntries(map.entries())
map을 key,value 쌍의 배열로 바꾸고 이를 다시 객체로 만들었습니다.

console.log(obj2) // {name: 'Lee', age: 27}

 

 

위 코드를 다음과 같이 줄여도 똑같이 동작합니다!

let obj2 = Object.fromEntries(map.entries())
--->
let obj2 = Object.fromEntries(map)

꼭 배열을 전달 할 필요는 없습니다.

Object.fromEntries는 인자로 iterable 객체도 받기 때문입니다.

map 자체가 iterable 객체입니다!!



 


 

Set

Set은 중복을 허용하지 않는 값을 모아놓은 컬렉션입니다.

 

  • new Set( iterable ) - Set을 만듭니다. iterable 객체를 전달 받으면( 대게 배열을 전달 받음 ) set에 값을 복사합니다.
  • set.add( value ) - value를 추가하고 set 자신을 리턴합니다.
  • set.has( value ) - set 내에 value의 유무를 Bollean으로 리턴합니다.
  • set.delete( value ) - value에 해당하는 값을 삭제합니다. 제거의 성공 여부를 Bollean으로 리턴합니다.
  • set.clear( ) - set의 모든 값을 제거합니다.
  • set.size - set에 저장된 값의 개수를 리턴합니다.

 

 

set.add( value )를 호출할 때 이미 set내에 value가 있다면, 무시됩니다.

let set = new Set()

let lee = { name : 'Lee'}
let kim= { name : 'Kim'}
let jin = { name : 'Jin'}

set.add(lee);
set.add(kim);
set.add(lee);
set.add(jin);
set.add(lee);

console.log(set)   // {{…}, {…}, {…}}
console.log(set.size) // 3

 

Set 대신 배열을 사용하고 방문자 정보를 저장한 후 arr.find( )를 이용해 중복 값 여부를 확인할 수 있습니다.

하지만 arr.find는 배열 전체를 뒤져 중복 값을 찾기 때문에, Set보다 성능 면에서 좋지 않습니다!

 

 


Set의 값으로 반복 작업하기

 

for..of 문 이나 forEach를 사용해서 set의 값을 대상으로 반복 작업을 할 수 있습니다.

set.forEach((value,valueAgain,set)=> {
  console.log(value,valueAgain,set)
});

// {name: 'Lee'} {name: 'Lee'} Set(3) {{…}, {…}, {…}}
// {name: 'Kim'} {name: 'Kim'} Set(3) {{…}, {…}, {…}}
// {name: 'Jin'} {name: 'Jin'} Set(3) {{…}, {…}, {…}}

for(let visitor of set){
  console.log(visitor)
}
// {name: 'Lee'},{name: 'Lee'},{name: 'Jin'}

forEach의 콜백 함수 파라미터에 같은 value가 2개나 있는 것은 Map과의 호환성 때문입니다. 

Map의 forEach에 쓰인 콜백이 3개의 파라미터를 받는 경우에 대비하기 위함입니다!

이런 구조 덕분에 Map을 Set으로 Set을 Map으로 교체하기가 쉽습니다!

 

 

 

Set 에도 Map에서 처럼 반복작업을 위한 메소드가 있습니다.

  • set.keys( ) - set의 모든 value를 포함하는 iterable 객체를 리턴합니다.
  • set.values( ) - set.keys( ) 와 동일한 작업입니다. 
  • set.entries( ) - set의 각 value를 이용해 만든 [ value , value ] 배열을 포함하는 iterable 객체를 리턴합니다.
let set = new Set(['Lee','Kim','Jin'])

console.log(set.keys()) // SetIterator {'Lee', 'Kim', 'Jin'}
console.log(set.values()) // SetIterator {'Lee', 'Kim', 'Jin'}
console.log(set.entries()) // SetIterator {'Lee' => 'Lee', 'Kim' => 'Kim', 'Jin' => 'Jin'}

 

 

요약 정리

 

Map은 key 타입의 제약이 없는 것이 특징

  • new Map( [ iterable ] ) - [key , value] 쌍이 있는 iterable을 선택적으로 넘길 수 있음. map 초기화에 사용됨
  • map.set( key,value ) - map의 새로운 key에 value를 저장하고 map 자신을 리턴
  • map.get( key ) - key에 해당하는 value리턴 key가 없으면 undefined 리턴
  • map.has( key ) - key의 유무를 Boolean으로 리턴
  • map.delete( key ) - key에 해당하는 값을 제거, 제거 성공 여부를 Boolean으로 리턴
  • map.clear( ) - map의 모든 요소 제거
  • map.size - map의 요소 개수 리턴

 

 

 

Set은 중복을 허용하지 않는 것이 특징

  • new Set( [ iterable ] ) - iterable 객체를 선택적으로 넘길 수 있음. set 초기화에 사용됨
  • set.add( value ) - set에 새로운 값을 추가하고 set 자신을 리턴, 이미 같은 값이 있을 경우 무시
  • set.has( value ) -value의 유무를 Boolean으로 리턴
  • set.delete( value ) - value에 해당하는 값을 제거, 제거 성공 여부를 Boolean으로 리턴
  • set.clear( ) - set의 모든 값 제거
  • set.size - set의 값 개수 리턴

 

Map과 Set에 반복 작업을 할 때 컬렉션에 요소나 값을 추가한 순서대로 반복 작업 수행.

정렬은 되어있으나 요소나 값을 재 정렬하거나 숫자를 이용해 특정 요소나 값을 가지고 오는 것은 불가능

 

 

 

 

 

기본이 중요하다!