백준에서 nodeJS 사용하기 (#03): 배열 - Array #4344번 #2562번 #1546번

Kyle Lee·2021년 10월 18일
0
post-thumbnail

1. 서론

알고리즘에서 빼놓을 수 없는 자료구조인 배열은 특히나 Javascript에서는 강력하게 사용할 수 있습니다. 편의성 높은 다양한 매서드를 통해 쉽고 빠르고 강력하게 알고리즘 문제들을 해결할 수 있죠. 알고리즘 테스트는 사실 논리적 사고와 프로그래밍 스킬을 함께보는 시험인데 Array 매서드를 자유자재로 활용할 수 있다면 매우 큰 도움이 될 수 있습니다.

매서드 공부를 안하면 이렇게 된다...

2. .map() vs .forEach()

두 매서드 다 배열을 순회하면서 반복문을 실행하는 함수입니다. 하지만 두 매서드의 차이점은, .map()은 각 배열의 요소에 'callback 함수'를 적용한(매핑한) 새로운 배열을 리턴하지만 .forEach()는 모든 배열의 요소를 순회하며 커스터마이징한 반복문을 실행할 수 있습니다.

쉽게 말하자면 .forEach().map()의 수퍼셋처럼 생각할 수 있습니다. (하지만 분명히 두 메서드의 쓰임새는 역할에 따라 다릅니다!)
두 매서드 다 기본 for문에 비하면 조금 느리지만 코드를 훨씬 간결하고 직관적으로 작성할 수 있어 가독성 높은 코드를 만들 수 있다고 생각합니다.

  • 예시
const array = [1, 2, 3, 4, 5];

// 단순 반복문을 실행 - ex) React에서 set, write 등의 기능을 수행할 때
array.forEach((elem) => doSomething(elem));

// 새로운 배열 객체를 리턴 - ex) React에서 새로운 JSX를 리턴할 때
const doubledArray = array.map((elem) => elem*2);

*자세한 비교분석

3. .filter()과 .reduce()

.filter()는 R이나 Python에 익숙하신 분들이라면 알고 계실 list comprehension 기능을 비슷하게 활용할 수 있도록 하는 메서드입니다. 해당 list, 즉 배열에 특정 조건문(필터)을 넣어 요소를 추출하는 메서드입니다.

// return : [5]
array.filter((elem) => array.includes(5));

// return : [2, 4]
array.filter((elem) => elem%2 === 0);

.reduce()는 사용자가 직접 만든 'reducer'함수를 각 배열 요소에 적용시키는 메서드입니다. 이 'reduce'라는 개념이 처음에는 혼란스러울 수 있는데, 쉽게 생각하면 각 배열을 요소를 'reducer 함수'에 넣어 누적값(acc) 얻는 형태라고 생각하면 쉽습니다. 복잡한 계산식을 '점화식'으로 압축시키거나 보편적이고 쉬운 계산으로 한단계 내리는 수학계산법 또한 'reduction'이라고 부르는 것처럼, 특정 배열을 어떠한 '압축기'나 '축소기'에 넣어 하나의 값을 얻는 형태라고 생각할 수 있습니다.

특정 함수를 적용해서 값을 추출한다는 점에서.filter와 비슷해보이지만, .filter는 조건문 함수(boolean)를 적용해 배열을 리턴하는 반면 .reduce()는 reducer 함수를 적용해 하나의 결과값을 리턴한다는 차이점이 있습니다.


이모지로 알아보는 쉬운 용례...

  • 예시
// return : 15
array.reduce((acc, elem) => acc + elem);

// return : [2, 4]
// acc의 초기값으로 2번째 인자인 '[]' 빈 배열을 설정함
// reduce로 구현한 짝수 filter
array.reduce((acc, elem) => {
	acc.push(elem % 2 === 0 && elem)
}, []);

*자세한 비교분석

4. .sort()

.sort()는 알고리즘 문제에서 자주 쓰이는 정렬 메서드이지만 JS에서는 조금 특별하게 쓰인다.
하지만 문제는 그냥 사용하게 된다면 .sort()는 배열의 요소를 'UTF-16'으로 문자 순서로 정렬하기 때문에 의도한 결과물이 나오지 않을 수 있다.

그렇기 때문에 숫자를 정렬할 때에는 .sort() 안에 callback 함수를 넣어서 자신이 원하는 정렬 방식을 지정할 수 있다.
callback 함수의 인자로 2개를 넣어서 리턴값이 양수인지 음수인지에 따라, 그 결과값이 하단과 같이 정렬된다.

  • 예시
// return : [5, 4, 3, 2, 1]
// b - a가 0보다 크다면 a가 b 앞으로 정렬
// b - a가 0보다 작다면 b가 a 앞으로 정렬
array.sort((a, b) => b - a);

5. 문제 4344번 - 평균은 넘겠지

해당 문제는 각 테이스 케이스마다 평균 이상의 학생 수를 구하는 문제입니다.
.reduce()를 통해 쉽게 전체 성적 총합을 구해 학생 수로 나누어서 해결할 수 있었습니다.

let input = require('fs').readFileSync('/dev/stdin').toString().trim().split('\n');
const caseNum = input.shift();

// 각 테스트 케이스를 순회하며 평균 계산
input.forEach((case) => {
    let arry = case.toString().split(' ').map(Number);
    // 학생 수 추출
    const students = arry.shift();
    // 성적 총합
    const total = arry.reduce((a, b)=> a+b, 0);
    let count = 0;
    arry.forEach((i) =>{
        if(i > total/students){
            // 평균이상의 학생 수 카운트
            count++;
        }
    });
    let answer = count/students*100;
    // 소수점 아래 3자리까지 퍼센트로 출력
    console.log(answer.toFixed(3)+'%');
});

6. 문제 2562번 - 최댓값

해당 문제는 주어진 배열에서 최댓값을 찾고 그 최댓값이 몇 번째 수인지를 구하는 문제입니다.
.sort()를 통해 쉽게 최대값을 구할 수 있습니다.

let input = require('fs').readFileSync('/dev/stdin').toString().split('\n');
// 위치 출력을 위한 배열 객체 복사
let arry = [...input];
// 오름차순으로 정렬
arry.sort((a, b) => a-b);
let highest = arry.pop();
let index = input.indexOf(highest);

console.log(`${highest}`);
console.log(`${index + 1}`);

7. 문제 1546번 - 평균

해당 문제는 최댓값을 기준으로 평균을 수정하는 문제입니다.
.map().sort(), .reduce()를 모두 활용해 통해 쉽게 최대값을 구하고 새로운 배열을 생성할 수 있습니다.

const input = require('fs').readFileSync('/dev/stdin').toString().split('\n');
// 성적의 수
const total = input[0];
// 성적 배열
const gradeArry = input[1].toString().split(' ');

// 정렬된 성적 배열
const sortedGrade = gradeArry.map(elem => Number(elem)).sort((a, b) => a-b);
const highest = sortedGrade[total-1];
// 수정된 성적의 총합
const revisedSum = sortedGrade.map(elem => 100*elem/highest).reduce((a, b) => a+b, 0);

console.log(revisedSum/total);
profile
필요에 의한 개발

0개의 댓글