백준 4344번 평균은 넘겠지-JS

yugyeongKim·2021년 10월 8일
0

백준

목록 보기
5/52
post-custom-banner

- 내가 짠 코드

const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : './input.txt';
let input = fs.readFileSync(filePath).toString().trim().split('\n');
let C = Number(input[0]); //케이스의 개수
let answer = '';
let sum = 0;
let avg = 0;
let count = 0;
let num = 100;
for(let i=1; i <= C; i++) {
    let arr = input[i].split(' '); // 각 케이스를 배열로 나타냄
    let N = Number(arr.shift());
    sum = 0;
    avg = 0;
    for(let j=0; j < N; j++) {
        sum = sum + Number(arr[j]);
    }
    avg = sum/N;
    count = 0;
    arr.forEach(element => {
        if(avg < element) {
            count++;
        }
    });
    let rate = (count/N*num).toFixed(3);
    answer += rate + '%\n';
}

console.log(answer);

첨에 진짜 누가봐도 맞는데(사실 안맞음) 안됐던 이유:
let N = Number(arr[0]) 이렇게 지정함
이렇게 했던 이유: 배열의 맨 처음에 갯수를 알려주는 거니 저걸 N값으로 써야지! 라고 생각했는데 예상치 못한 문제는 foreach에서 나타났다.
다시 꼼꼼히 보니 안됐던 이유가 foreach는 배열의 모든 요소에 함수를 돌리는데 즉, arr[0]부터 arr[5]까지 돌린다. 하지만 arr[0]은 우리가 더해줘야 하는 값이 아니고 갯수이다. 그러므로 평균을 넘는 "점수" 를 확인하는 함수에서 쓰이는게 아니다. 아마 이러한 이유로 틀린것 같다. shift로 아예 맨 앞값을 빼버리니 제대로 작동하는 것을 보면 아마 내추측이 맞지 않을까

- 다른 사람 코드

const fs = require('fs').readFileSync('/dev/stdin').toString().split('\n')

for (let i = 1; i <= fs[0]; ++i) {
  let A = fs[i]
    .trim()
    .split(' ')
    .map((x) => +x)
  let B = A.slice(1).filter(
    (x) => x > A.slice(1).reduce((a, b) => a + b) / A[0],
  )

  console.log(((B.length / A[0]) * 100).toFixed(3) + `%`)
}

오 이게 듣기만 하던 Map..~

- 두번째로 짠 코드

const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : './input.txt';
let input = fs.readFileSync(filePath).toString().trim().split('\n');
let C = Number(input[0]); //케이스의 개수
let answer = '';
let num = 100;

for(let i=1; i <= C; i++) {
    let arr = input[i].split(' '); // 각 케이스를 배열로 나타냄
    let N = Number(arr.shift());
    let avg = 0;
    
    let map_arr = arr.map(element => Number(element));
    let a = map_arr.reduce(function(accumulator, currentValue) {
        return accumulator + currentValue;
      });
    
    avg = a/N;
    let count = 0;
    arr.forEach(element => {
        if(avg < element) {
            count++;
        }
    });
    let rate = (count/N*num).toFixed(3);
    answer += rate + '%\n';
}

console.log(answer);

map과 reduce를 이용해서 더 간결하게 만들었는데 왜 그닥 안간결해진거 같지...? 아무튼 시간이랑 메모리는 확실히 줄었다. 다른 사람거처럼 더 능숙하게 map이랑 reduce쓰면 더욱 간결해질듯

- 세번째 코드(다른사람거 참고)

const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : './input.txt';
let input = fs.readFileSync(filePath).toString().trim().split('\n');
let C = Number(input[0]); //케이스의 개수
let answer = '';
let num = 100;

for(let i=1; i <= C; i++) {
    let scoreSum = input[i].split(' ').map((x) => +x); // 점수들의 배열
    let highScore = scoreSum.slice(1).filter(
        (x) => x > scoreSum.slice(1).reduce((a,b) => a+b) /scoreSum[0]
    );
    let rate = (highScore.length / scoreSum[0] * 100).toFixed(3);
    answer += rate + '%\n';
}

console.log(answer);

map과 reduce를 적절히 사용하면 이렇게 간결해진다. 근데 훨씬 느리고 메모리도 많이 소요되긴함 흠....ㅁㄹ
그리고 문자로된 숫자 배열을 arr.map((x) => +x) 이렇게 하니까 숫자로된 배열로 바뀜.
아 그리고 map(Number)이렇게 해도 숫자배열로 반환됨!

- 새로 알게 된 점

  • Map & reduce
    정리해둠

  • slice
    slice(start,[end])
    -start: 추출 시작점에 대한 인덱스.
    undefined인 경우: 0부터 slice
    음수를 지정한 경우: 배열의 끝에서부터의 길이를 나타낸다. slice(-2)를 하면 배열의 마지막 2개의 요소를 추출한다.
    배열의 길이와 같거나 큰 수를 지정한 경우: 빈 배열을 반환한다.
    -end: 추출을 종료할 기준 인덱스. (end를 제외하고 그 전까지의 요소만 추출한다.)
    지정하지 않을 경우: 배열의 끝까지 slice
    음수를 지정한 경우: 배열의 끝에서부터의 길이를 나타낸다. slice(2, -1)를 하면 세번째부터 끝에서 두번째 요소까지 추출
    배열의 길이와 같거나 큰 수를 지정한 경우: 배열의 끝까지 추출
    반환값: 추출한 요소를 포함한 새로운 배열.

출처: https://im-developer.tistory.com/103 [Code Playground]

  • 문자열 숫자배열을 숫자배열로 바꾸는 법(map이용)
    -arr.map((x) => +x)
    -arr.map(Number)

- 느낀점

  • 처음 짠 코드때 느낀점
    그냥 앵간하면 앞으로 배열 앞에 값알려주는거 arr[0]이런식으로 하지말고 걍 shift로 뽑아내자....^^
  • 두번째
    map, reduce 짱신기, 역시 필터는 좋아
post-custom-banner

0개의 댓글