배열의 중복 요소의 개수 ❓

송철진·2023년 1월 13일
0

reduce로 구현

const arr = [1,2,3,4,5,6,7,8]

const count2 = arr.reduce( (ac, v) => {
    v in ac ? ac[v]++ : ac[v] = 1
    return ac;
  }, {});

const count3 = arr.reduce( (ac, v) => {
    ac[v] = ( ac[v] || 0 ) + 1 
    return ac
  }, {})

reduce, spread로 구현

const arr = [1,2,3,4,5,1]

const count = arr.reduce( (ac,v) => ({...ac, [v] : ( ac[v] || 0 ) + 1 }), 0)

console.log(count)

위커뮤니티에 올라온 글 중에 흥미로운 코드가 있어서 살펴보게 되었다
프로그래머스 풀 때 이런 논리를 기반으로 이것저것 선언,할당해서 코드가 길어지곤 했는데 이 기회에 reduce 메서드와 spread 연산자로 더 간단하게 짜는 법에 익숙해지고자 한다.

  • 배열 arr의 값을 순회하여
  • 객체의 키에 해당하는 현재 값v,
  • 초기값 0,(=> "",[], {} 여도 상관없음)
  • 누적값 ac에 키 v로 접근한 값이 없으면 0, 있으면 +1

의문❓

원문: ✅

const count = arr.reduce( (ac,v) => ({...ac, [v] : ( ac[v] || 0 ) + 1 }), 0)

화살표 다음에 괄호()를 지우면? ❌
👉 왜 지우면 안될까?

const count = arr.reduce( (ac,v) => {...ac, [v] : ( ac[v] || 0 ) + 1 }, 0)

Uncaught SyntaxError: Rest parameter must be last formal parameter

추측: 화살표 함수의 규칙?
화살표 함수에서는 {}가 객체 자체를 반환하는 건지, 함수 블록인지 판단하기 어려우니까 객체 자체를 반환하는 거라면 ({})처럼 묶어주는게 아닌가 싶다

const a1 = x => ({...x})

function a2(x){ return {...x} }

console.log(a1("a"))
console.log(a2("a"))

화살표 함수를 function으로 쓰면 ✅

const count = arr.reduce( function(ac,v){   
  return ({ ...ac, [v] : ( ac[v] || 0 ) + 1 })
}, 0)

return 다음에 ()를 지우면? ✅

const count = arr.reduce( function(ac,v){   
  return { ...ac, [v] : ( ac[v] || 0 ) + 1 }
}, 0)

초기값을 string으로 하면?

const arr = [1,2,3,4,5]
const count4 = arr.reduce( (ac,v) => 
  ({ ...ac, [v] : ( ac[v] || 0 ) + 1 }), "abc")
console.log(count4)

"abc"를 spread 해서 {}에 초기값으로 할당하면

ac = { "0":"a", "1":"b", "2":"c" }

ac[v]에 값이 있으면 ac[v]+1, 없으면 0+1

// v = 1 일 때 존재하므로 +1
ac = { "0":"a", "1":"b1", "2":"c" }

// v = 2 일 때 존재하므로 +1
ac = { "0":"a", "1":"b1", "2":"c1" }

// v = 3 일 때 없으므로 0+1
ac = { "0":"a", "1":"b1", "2":"c1", "3":1 }

// v = 4 일 때 없으므로 0+1
ac = { "0":"a", "1":"b1", "2":"c1", "3":1, "4":1 }

// v = 5 일 때 없으므로 0+1
ac = { "0":"a", "1":"b1", "2":"c1", "3":1, "4":1, "5":1 }

초기값을 string으로 & 순서를 바꾸면?

const arr = [1,2,3,4,5]
const count3 = arr.reduce( (ac,v) => 
  ({ [v] : ( ac[v] || 0 ) + 1, ...ac }), "abc")
console.log(count3)

ac[v]에 값이 있으면 ac[v]+1, 없으면 0+1

// v = 1 일 때 없으므로 0+1
ac = { "1":1 }

// v = 2 일 때 없으므로 0+1
ac = { "1":1, "2":1 }

// v = 3 일 때 없으므로 0+1
ac = { "1":1, "2":1, "3":1 }

// v = 4 일 때 없으므로 0+1
ac = { "1":1, "2":1, "3":1, "4":1 }

// v = 5 일 때 없으므로 0+1
ac = { "1":1, "2":1, "3":1, "4":1, "5":1 }

"abc"를 spread 해서 {}할당하면

ac = { "0":"a", "1":"b", "2":"c", "3":1, "4":1, "5":1 }

...라고 생각했는데❓

다음 실행 결과는 { "0":"1", "1":"2" }이 되어야 하지 않을까? 왜 "12"일까?
arr에 상관없이 무조건 ac를 spread연산하는게 우선이라고 생각했는데
왜지.. arr에 값이 없거나 공백이면 초기값 그대로 산출되는 조건이 있나?

const arr = [] // [ ] 도 동일한 결과
const count1 = arr.reduce( function(ac,v){   
  return ({ ...ac, [v] : ( ac[v] || 0 ) + 1 }) }, "12")

const arr = [[]] // [""] 도 동일한 결과
const count1 = arr.reduce( function(ac,v){   
  return ({ ...ac, [v] : ( ac[v] || 0 ) + 1 }) }, "12")

const arr = [{}]
const count1 = arr.reduce( function(ac,v){   
  return ({ ...ac, [v] : ( ac[v] || 0 ) + 1 }) }, "12")

profile
검색하고 기록하며 학습하는 백엔드 개발자

0개의 댓글