ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 배열에 접근하는 방법들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))
Designed by Tistory.