-
배열에 접근하는 방법들2 : set(), map(), 배열의 중복제거JavaScript 2022. 9. 28. 18:52
배열에서 중복 없애기 : 조건문 노가다, set, filter 등
let arr = [1,1,3,3,3,0,0,1,1,1,1] function solution(arr) { let array = []; for(let i=0; i<arr.length; i++){ if (arr[i]!==arr[i+1]){ array.push(arr[i]) } } return array; } console.log(solution(arr)) // [ 1, 3, 0, 1 ]
const arr = [1,1,3,3,0,1,1] const arr2 = [...new Set(arr)] console.log(arr2) // [ 1, 3, 0 ]
function solution(arr) { return arr.filter((val,index) => val != arr[index+1]); }
set 은 순서에 상관 없이, 중복된 것을 배열에 담지 않는다.
"Set 객체는 자료형에 관계 없이 원시 값과 객체 참조 모두 유일한 값을 저장할 수 있습니다." 라는 것이 mdn 문서의 표현이다.
// foreach 로 돌리면서 검사 arr = ['Seoul','Busan','Jeju'] let isExistEoul = false; arr.forEach(item => { if (item=='Seoul') isExistSeoul = true; }) //set의 내장함수로 검사 let arr2 = new Set(arr) console.log(arr2.has('Seoul')) // true
그러므로 내장함수로 배열 내 요소의 값을 검사하기 좋다.
mdn 문서의 예제를 보면 (매우 이례적으로!) set의 작동방식에 대해 대강은 짐작할 수 있다.
var mySet = new Set(); mySet.add('foo'); mySet.has('foo'); // true mySet.has('bar'); // false var set1 = new Set(); var obj1 = {'key1': 1}; set1.add(obj1); set1.has(obj1); // true set1.has({'key1': 1}); // false, 형태만 같은 서로 다른 객체의 참조이기 때문 set1.add({'key1': 1}); // set1의 요소가 2개로 늘어남
function solution(numbers) { const result = [] for(i=0; i<numbers.length; i++){ for(j=0; j<numbers.length; j++) { const x = numbers[i] const y = numbers[j] if(i!==j){result.push(x+y)} } } return [...new Set(result)].sort((a,b)=>a-b)
간단한 숫자놀이라도, 반환할 배열의 중복된 요소들 때문에 골치아플 때가 많다.
이 때 set객체 생성은 훌륭한 대안이다.
Map.prototype.set()
map.set() 메서드는 맵 객체에 key : value 형태 자료형을 들여놓는다.
set(key, value) // 웬일로 엄청나게 심플한 MDN 문서의 구문
const map1 = new Map(); map1.set('bar', 'foo'); console.log(map1.get('bar')); // expected output: "foo" console.log(map1.get('baz')); // expected output: undefined
const myMap = new Map(); // Add new elements to the map myMap.set('bar', 'foo'); myMap.set(1, 'foobar'); // Update an element in the map myMap.set('bar', 'baz');
// Add new elements to the map with chaining. myMap.set('bar', 'foo') .set(1, 'foobar') .set(2, 'baz');
map은 key : value 를 넣기에 아주 좋은 객체였다.
Map.prototype.get()
map.get() 은 맵 객체에서 특정 키와 관련된 특정 요소를 반환한다. 그런거 없으면 undefined 반환.
get(key) // 이게 구문의 끝이다...
const map1 = new Map(); map1.set('bar', 'foo'); console.log(map1.get('bar')); // expected output: "foo" console.log(map1.get('baz')); // expected output: undefined
const arr = []; const myMap = new Map(); myMap.set('bar', arr); myMap.get('bar').push('foo'); console.log(arr); // ["foo"] console.log(myMap.get('bar')); // ["foo"]
이를 통해 Map 은 기본적으로 key:value 형태의 객체로서 고안되었음을 알 수 있다.
만날 문제풀이용 도구로나 소모하니까 몰랐지, get() 과 push() 로 내부에 관여할 수도 있는 딕셔너리형태 자료가 map인듯 하다.
get()으로 키를 누르면, value가 튀어나온다.
그러므로, 소소하게 정답을 출력했던 나에게 map 메소드가 일갈한다.
const participant = ["mislav", "stanko", "mislav", "ana"] const completion = ["stanko", "ana", "mislav"] function solution(participant, completion) { participant.sort(); completion.sort(); for(let i=0; i<participant.length; i++) { if(participant[i] !== completion[i]) { return participant[i]; } } } console.log(solution(participant, completion)) // mislav
const participant = ["mislav", "stanko", "mislav", "ana"] const completion = ["stanko", "ana", "mislav"] function solution(participant, completion) { const map = new Map(); for(let i = 0; i < participant.length; i++) { let a = participant[i], b = completion[i]; map.set(a, (map.get(a) || 0) + 1); map.set(b, (map.get(b) || 0) - 1); console.log(map.get(a)) console.log(map.get(b)) // for문 돌릴때마다 콘솔 찍어보니 열심히 카운팅 중이더라. } for(let [k, v] of map) { if(v > 0) return k; } return 'nothing'; } console.log(solution(participant, completion)) // mislav
map.set 메소드로 map에 새로운 객체를 추가.
map.set(key, value)형태. key 영역에는 a, 즉 participant의 첫번째 요소부터 들어간다.
value값으로 (map.get(a) || 0) + 1
a가 처음 추가되는 상황이므로 map.get(a)가 false (undefined). 튀어나와야할 value 값이 없다. 0이 출력.
거기에 +1을 하니 결과적으로 key에 a, value에 1이 map에 저장.
이후 반복문에서는?
map에 a가 이미 추가되어있는 상황이라면(동명이인, 위 예제에서는 mislav) 가 들어오더라도
map에 key가 a value가 1인 객체가 있으므로,
map.get(a)가 true가 되어 (map.get(a) || 0)에서 map.get(a)가 1을 반환.
거기에 +1을 하면 a의 value값으로 2가 전달.즉, map은 key 값 별로 참석자 머릿수 카운팅을 하고 있는 것이다!
이제 b로 완주자 이름이 들어온다. 예컨대 competition[1] stanko.
stanko의 이름이 이미 map에 있다면 (즉 완주자라면)
(map.get(b) || 0) 에서 1이 튀어나온다.그리고 -1, value값이 0이 된다.
즉, map은 key 별로 완주자는 값을 뺄셈하고 있다!
결국 완주를 못하고 a만 있던 사람의 이름.
그 사람만이 value값이 1인상태로 남게 된다. (mislav의 경우)
동명이인인 mislav는 a에서 한번더 1이 더해져 value가 2인상태에서 b에서 1을 뺀다고 해도 값이 1이 남는다.
그리고 마무리, 아래 for 문에서 value값이 0이상 즉 1 인 key(미완주자, 동명이인)를 출력한다.
Map 에서 filter 돌리기
https://stackoverflow.com/questions/48707227/how-to-filter-a-javascript-map
How to filter a JavaScript Map?
Given an ES6 Map and predicate function, how do I safely delete all non-matching elements for the map? I could not find an official API function, but I can think of two implementations. The first ...
stackoverflow.com
map 에는 filer 와 관련된 연산자가 없다.
그래서 가공이 필요하다.
1. 맵을 key : value 쌍으로 변환한다.
2.그걸 스프레드로 펼친다.
3.필터를 먹인다.
4.다시 맵으로 돌아온다.
const map0 = new Map([ ['a', 1], ['b', 2], ['c', 3] ]); const map1 = new Map( [...map0] // A different way of writing [...map0] is Array.from(map0) .filter(([k, v]) => v < 3 ) ); console.info([...map1]); //[0: ["a", 1], 1: ["b", 2]]
function solution(arr, n){ let map1 = new Map(); for(let i = 0; i < arr.length; i++) { let a = arr[i]; map1.set(a, (map1.get(a) || 0) + 1); } //console.log(map1) let map2 = new Map([...map1].filter(([k, v]) => v < 2 )); //console.log(...map2) let arr2 = Array.from (map2.keys()) //console.log(arr2) return(arr2.sort().sort((a,b) => a.charCodeAt(n) - b.charCodeAt(n))) } let arr = ["coke", "water", "glass", "dog", "dog", "yogurt", "vitamin"]; let n =2 console.log(solution(arr, n))
'JavaScript' 카테고리의 다른 글
문자열과 숫자에 접근하는 방법들3 : 정규표현식 (0) 2022.09.28 문자열과 숫자에 접근하는 방법들 2 : sort() (0) 2022.09.28 조건을 거는 방법들 1 : while, do while 등 (0) 2022.09.28 문자열과 숫자에 접근하는 방법들 1 : +, isNan() 등 (0) 2022.09.28 배열에 접근하는 방법들 1 : forEach(), filter (0) 2022.09.28