프로그래머스 Lv.1 정수 내림차순으로 배치하기 문제를 풀며 정리한 내용입니다.
문제 설명
함수 solution은 정수 n을 매개변수로 입력받습니다. n의 각 자릿수를 큰것부터 작은 순으로 정렬한 새로운 정수를 리턴해주세요. 예를 들어 n이 118372면 873211을 리턴하면 됩니다.
제한 조건
- n은 1이상 8000000000 이하인 자연수입니다.
function solution(n) {
let sortArr = (n+'').split('').map((str)=> parseInt(str)).sort((a,b)=> b-a)
let num = parseInt(sortArr.reduce((acc,cur)=> acc+String(cur)))
return num
}
내가 작성한 코드는 정수를 각 자릿수 별 쪼개고 sorting한 뒤에 문자열 방식으로 각 자릿수를 더하는 방식이다.
즉, 정수→문자→정수→문자→정수
이렇게 타입을 계속적으로 변환해줘야 한다.
아무리 봐도 비효율적이었지만, 아직 JS의 함수 메서드를 많이 모르기 때문에 아는 선에서 최선을 다해 그나마 풀었던 코드이다..
일단 sort
메서드에 대한 낮은 이해도 때문에 map
메서드를 불필요하게 사용했었다. 따라서 이를 제외하고 reverse
메서드와 join
메서드를 사용하고 +
를 연산자를 사용하면서 보기 좋은 코드로 완성할 수 있었다.
function solution(n) {
let sortArr = (n+'').split('').sort().reverse()
let changeNum = sortArr.join('')
return +changeNum
}
그래서 공부하게 된 함수 메서드는 array와 함께 사용하는 sort()
, reverse()
, join()
이다.
sort 메서드의 유의해야할 점을 먼저 살펴보자.
- 상식적으로 생각하는 오름차순 방식이 아닌 문자열의 유니코드 코드 포인트를 따른다.
- 원 배열이 복사되는 것이 아닌 원 배열이 정렬된다.
[예시 코드1]
const strArr = ['Minngki', 'World', 'Hello', 'Debugging']
console.log(strArr.sort()) // ['Debugging', 'Hello', 'Minngki', 'World']
const numArr = [1, 5, 2, 200, 10]
console.log(numArr.sort()) // [1, 10, 2, 200, 5]
문자열 배열인 strArr
은 우리의 예상대로 반환되었지만 숫자형 배열인 numArr
은 우리가 예상했던 방향인 [1, 2, 5, 10, 200]
값으로 반환되지 않는다는 것이다.
그렇다면 이 방식대로 반환하기 위해서는 어떻게 코드를 작성해야 할까 ?
sort
함수의 구문을 살펴보자.
arr.sort([compareFunction])
compareFunction
은 정렬 순서를 정의하는 함수로, 원하는 방식의 정렬을 정의해주면 된다. 이를 생략하면 문자열 유니코드 코드 포인트 값에 따라 정렬이 되는 것이다.
[예시 코드2]
const numArr = [1, 5, 2, 200, 10]
console.log(numArr.sort((a, b) => a-b)) // [1, 2, 5, 10, 200] - 오름차순
console.log(numArr.sort((a, b) => b-a)) // [200, 10, 5, 2, 1] - 내림차순
a-b
? b-a
? 이 차이는 무엇일까 ?
왜 이렇게 작동하는지 자세히 살펴보자면, compareFunction
의 원리는 다음과 같다.
compareFunction
원리function compare(a, b) {
if (a < b) {
return 음수;
} // compare 함수가 음수를 반환하면 a를 b보다 낮은 index로 정렬하므로, a가 먼저 와야 한다.
if (a > b) {
return 양수;
} // compare 함수가 양수를 반환하면 b를 a보다 낮은 index로 정렬하므로, b가 먼저 와야 한다.
if (a == b) {
return 0;
} // compare 함수가 0을 반환하면 a와 b는 순서를 바꾸지 않는다.
}
compare
함수의 인자에 따른 반환값이 음수
, 양수
, 0
냐에 따라 정렬 방식이 달라진다는 것이다.
compareFunction
[예시 코드2]로 돌아와보자면,
const numArr = [1, 5, 2, 200, 10]
console.log(numArr.sort((a, b) => a-b))
// 1-5 = -4 음수이므로 1이 5보다 낮은 인덱스, 5-2 = 3 양수이므로 2가 5보다 낮은 인덱스 (반복)
console.log(numArr.sort((a, b) => b-a))
// 5-1 = 4 양수이므로 5가 1보다 낮은 인덱스, 1-2 = -1 음수이므로 2가 1보다 낮은 인덱스 (반복)
이 예시는 문자열이 아닌 숫자를 비교하기 위한 compare
함수이며, 원소에는 Infinity
및 NaN
이 포함되어 있지 않아야 한다.
해당 함수는 숫자 간의 단순계산을 하여 음수
, 양수
, 0
이 세 가지가 모두 반환이 가능하므로 정상 작동한다.
그러나! 문자열을 비교하는 compare
함수를 작성할 시 주의할 점이 있다.
compareFunction
compareFunction
의 반환값은 항상 음수
, 0
, 양수
의 값을 반환해야 한다.
양수
/음수
만 반환한다거나 음수
/0
만 1-2가지의 값을 반환하면 원하는 방향의 정렬을 하지 못 할 것이다.
따라서, 문자열을 비교할 때 compareFunction을 작성할 땐 세 가지 경우의 if문을 사용해야 한다는 것을 유의하자!
[추가 - 문자열]
문자열을 비교할 때, 일반적으로 영문 대소문자 중 대문자가 앞에 온다. (오름차순이라면 대-소 순서)
Object의 프로퍼티를 이용해서 내부의 정렬을 정의할 수 있다.
[예시 코드3]
const market = {
name: 'emart',
fruits: [
{
name: 'banana',
price: 2000,
},
{
name: 'apple',
price: 3000,
},
{
name: 'cherry',
price: 1000,
}]}
market.fruits.sort((a,b)=> {
return a.price-b.price })
console.log(market)
// {
// name: 'emart',
// fruits: [
// {
// name: 'cherry',
// price: 1000,
// },
// {
// name: 'banana',
// price: 2000,
// },
// {
// name: 'apple',
// price: 3000,
// }]
문자열인 market.fruits.name도 정렬이 가능하다.
// 오름차순 기준, 내림차순이면 각 연산자를 반대로 설정해주면 된다.
market.fruits.sort((a,b)=> {
if (a.name < b.name) {
return -1
}
if (a.name > b.name) {
return 1
}
return 0
})
// {
// name: 'emart',
// fruits: [
// {
// name: 'apple',
// price: 3000,
// },
// {
// name: 'banana',
// price: 2000,
// },
// {
// name: 'cherry',
// price: 1000,
// }
// ]
if문을 사용해서 정렬에 대한 조건을 직접 정의할 수 있다.
[예시 코드4]
const numArr = [0, 0, 0, 3, 4, 2];
numArr.sort((a,b)=>{
if (a===0) { // 앞에 있는 원소가 0이라면 1(양수)을 반환하여 0이 아닌 다른 수를 낮은 인덱스로 취하고,
return 1;
} else if (b===0) { // 뒤에 있는 원소가 0이라면 -1(음수)을 반환하여 0이 아닌 다른 수를 낮은 인덱스로 취한다.
return -1;
} else { // 비교하는 원소가 모두 0이 아니라면 오름차순을 취해 반환한다.
return a-b;
}
} // [2, 3, 4, 0, 0, 0]
그래서 예전에 공부할 때도 sort 함수를 마구잡이로 활용해선 안 되겠다 란 강렬한 인상이 남아서인지, 이번 연습문제를 풀 때는 완전 꼬아서 생각했다.
연습문제에서는 어차피 한 자릿수로 쪼개서 비교하는 것이기 때문에 두 자리에서의 문자열 유니코드를 굳이 고려하지 않고 간단하게 reverse
메서드를 사용했으면 됐었다.
원 배열의 순서를 반전하여 변형된 원 배열을 반환한다. 원 배열의 인덱스를 내림차순으로 변형시키는 메서드라 생각하면 쉽다.
array.reverse()
[예시 코드5]
const arr = [1, 2, 3]
const reverseArr = arr.reverse()
console.log(reverseArr) // [3, 2, 1]
// 주의 !
console.log(arr) // [3, 2, 1] - 원 배열도 reverse된 형태로 변형된다.
console.log(arr[0]) // 3 - 인덱스도 변경된다.
join 메서드는 배열의 모든 요소를 연결하여 하나의 문자열로 반환한다.
array.join([seperator])
seperator
는 배열의 각 요소를 연결할 때 구분할 문자열이다. 생략하면 배열의 요소가 쉼표로 구분이 되고, 빈 문자열이면 아무 문자 없이 연결된다.
[예시 코드6]
const array = ['min','ng','ki'];
console.log(array.join()); // 'min,ng,ki'
console.log(array.join('')); // 'minngki'
console.log(array.join('-')); // 'min-ng-ki'
알고나면 너무나 쉬운 join 메서드..
이 꿀 같은 join 메서드를 항상 잊는다..바보처럼..
잊지말자.. join...
https://developer.mozilla.org/ko/
https://brunch.co.kr/@swimjiy/12