Your task is to add up letters to one letter.
The function will be given a variable amount of arguments, each one being a letter to add.
Notes:
Examples:
- addLetters('a', 'b', 'c') = 'f'
- addLetters('a', 'b') = 'c'
- addLetters('z') = 'z'
- addLetters('z', 'a') = 'a'
- addLetters('y', 'c', 'b') = 'd' // notice the letters overflowing
- addLetters() = 'z'
🎯 문제설명
주어진 문자(알파벳 a부터 z까지)를 다 더한 후, 더한 값에 해당하는 문자로 다시 반환하시오. overflowing(더한 값이 z를 넘어가는 경우)일 경우는 다시 처음부터(a부터) 시작하여 계산해서 해당하는 값을 반환하시오.
이 문제를 숫자와 문자(알파벳) 사이의 변환을 어떻게 할 것인가를 묻는 문제이다. 사실 자바에서는 이것에 대해서 굉장히 편했다고 생각한다. 자바에서는 자동형변환이라는 편리한 규칙(?)이 있기 때문이다. 문자(char)와 문자(char)를 더했을 때, 문자 표현범위의 값을 넘어서면 자동으로 숫자(int)로 바꿔서 출력해주었기 때문에 알파벳을 숫자로, 숫자를 알파벳으로 바꿔서 생각하는게 그렇게 어렵지 않았다.
System.out.println('a'+'A'); //97+65 = 162 : 자동형 변환
System.out.println('a'); //a : 변환 없음(아스키코드안의 값 a = 97)
System.out.println((char)65); //A : 강제형 변환
자동형 변환이란?
자동형 변환의 원칙은 표현범위가 좁은 데이터 타입에서 넓은 데이터 타입으로의 변환만 허용된다는 것이다.
아래 이미지를 보면 화살표방향으로의 형변환은 자연스럽게 되지만 반대방향(강제형변환)으로의 변환은 명시적으로 형변환에 대한 표시를 해야한다.
이제 자바스크립트이다. 자바스크립트는 어떻게 문자(알파벳)와 숫자를 변환할 수 있을까? 자바스크립트에서는 2가지의 String 메소드가 존재한다.
String.charCodeAt(문자열의 인덱스) : 해당 character -> unicode number
String.fromCharCode(유니코드 숫자) : unicode number -> 해당 character
두가지의 메소드를 잘 조합해서 문제를 풀면 되었다. 그래도 숫자 계산을 해야만 해서 조금 시간이 걸렸다.
function addLetters(...letters) {
let sum = 0;
for(let value of letters){
sum += (value.charCodeAt(0)-96);
}
return sum % 26 === 0 ? 'z' : String.fromCharCode(sum % 26 + 96);
}
여기서 시간이 걸린 이유는 단순히 산수 때문이였다. 시작 값을 1로 해야하는가 혹은 95를 빼야하는가, 기준점을 어디서 잡아야해야 편할까? 등등을 결정하는데 오류가 생겼다.
function addLetters(...letters) {
return String.fromCharCode((letters.reduce((a, b) => a + b.charCodeAt(0) - 96, 0) + 25) % 26 + 97);
}
reduce()는 생각지도 못한 곳에서 나온다. 지금까지 reduce()가 사용되어진 상황을 종합하자면, 어떠한 배열에서 한가지의 결과를 추출하고자 하면 reduce()는 언제든 사용 가능한 것 같다. 나도 이제 reduce()를 강제적으로라도 써보려는 노력을 해봐야겠다.
어떤 친철한 외국인 친구가 이 풀이에 대해서 설명을 해놓았다.
1. adding up all the letters charcodes, -96 to convert from charcode to position in the alphabet
2. +25 to handle multiples of 26 having a wrong value when calling %
(26으로 나머지 연산을 할 때, reduce() 결과값 0 이 a가 될 수 있도록 순서를 맞춘 것)
3. mod 26 to loop around the alphabet
4. converting it back to a letter charcode by adding 97
5. returning a string from that charcode
var alphabet = 'abcdefghijklmnopqrstuvwxyz';
function addLetters(...letters) {
var sum = 25;
for (var letter of letters)
sum += alphabet.indexOf(letter) + 1;
return alphabet[sum % 26];
}
사람들은 뭔가 신기하고 특별한 방법을 사용해서 문제를 해결하면 대단하다고 생각하는 경향이 있다. 그런데 나는 1번 풀이보다 2번 풀이가 훨씬 더 좋은 풀이라고 생각하다. 직관적이고 이해하기 쉽다는 점에서 그렇다. 알파벳은 변하지 않기 때문에 상수화를 하여 그것의 인덱스 값을 통해서 접근하는 방법은 굳이 새롭고 어렵운(?) 메소드를 찾을 필요가 없다. 알고 있는 범위 내에서 해결이 가능했던 것이다.
알고 있었다고 생각하는 것들을 다시 글로 써내려가면 내가 얼마나 모르고 있었는지를 알 수 있게 된다. 내가 글로 쓰면서도 이건 도대체 무슨 소리를 하는거야 라며 다시 찾아보게 된다. 안타깝지만 한번에 모든걸 다 완벽하게 알 수는 없다고 생각한다. 모르면 모를때마다 계속 찾아보면서 구멍을 채워나갈 수 밖에 없는 것 같다.
🚀 문제를 풀어나갈 때 생각의 흐름을 정리합니다. 또한 새로운 풀이에 대한 코드를 분석하고 모르는 부분에 대해서 정리합니다. 생각이 다른 부분에 대한 피드백은 언제나 환영합니다. 틀린 내용에 대한 피드백 또한 항상 감사합니다.
형변환
자바 형변환
JavaScript String fromCharCode() Method
JavaScript String charCodeAt() Method