Persistent Bugger<6 kyu>

jjanmo·2020년 1월 7일
0

Codewars에서 뒹굴기

목록 보기
13/32

문제링크

문제

Write a function, persistence, that takes in a positive parameter num and returns its multiplicative persistence, which is the number of times you must multiply the digits in num until you reach a single digit.

For example:

 persistence(39) === 3 // because 3*9 = 27, 2*7 = 14, 1*4=4
                       // and 4 has only one digit
 persistence(999) === 4 // because 9*9*9 = 729, 7*2*9 = 126,
                        // 1*2*6 = 12, and finally 1*2 = 2
 persistence(4) === 0 // because 4 is already a one-digit number

🚩 문제해석
주어진 숫자(parameter)를 한자리씩 곱해서 나온 수가 한자리 수가 될 때까지 몇 번을 반복해야 하는지를 구해서 그 반복횟수를 결과값으로 리턴하시오. 이미 주어진 수가 한자리 수라면 반복 횟수가 없기때문에 결과값은 0이 된다.(example)

문제접근

  • 첫번째 생각
    / 와 %를 이용하여 숫자로 접근해서 풀어볼까?

  • 첫번째 풀이

    ```javascript
    	function persistence(num) { 
    		let cnt = 0; 
    		while(num >= 10){ 
    			let mul = 1; 
    			let tmp = num; 
    			while(tmp > 0){ 
    				mul *= tmp % 10; 
    				tmp = Math.floor(tmp / 10); 
    			} 
    			num = mul; cnt++; 
    		} 
    		return cnt; 
    	}
    ```

    while문을 사용한 이유는 주어진 수가 몇자리 수가 될지 알 수가 없기 때문이다. 또한 몇 번을 반복하면 되는지도 알 수가 없다. 결국 2번의 while문을 사용할 수 밖에 없었다.

  • 두번째 생각
    각 자리수를 배열에 넣으면 자리수로 접근하기가 수월하니까 우선 배열로 바꿔서 풀어볼까?

  • 두번째 풀이

    	```javascript
    		function persistence(num) { 
    			let cnt = 0; 
    			while(num >= 10){ 
    				num = String(num).split('').reduce((a,v)=>Number(a)*Number(v),1); 
    				cnt++; 
    			} 
    			return cnt; 
    		}
    	```

Best Solution

const persistence = num => {
  return `${num}`.length > 1 
		  ? 1 + persistence(`${num}`.split('').reduce((a, b) => a * +b)) 
		  : 0;
}

재귀적 풀이. 항상 반복하는 경우에 재귀적 풀이가 가능하다. 하지만 재귀적인 접근을 안하게된다, 대신 반복문을 주로 사용한다. 아마도 익숙해서 그런것같다. 또 재귀적 접근은 항상 stack overflow 의 이슈를 갖고 있다. 그럼에도 이 코드는 적재적소에 ES6 문법을 잘 사용하였다. 어떤 식으로 ES6를 사용했는지 알아보자.

첫번째는 Number타입을 String타입으로 바꾸는 방법이다. 이 부분을 template literals이라는 문법을 사용하였다.

  • Template Literals
    " " or ' '를 통해서 문자열을 만드는 대신 ``(백틱, grave accent) 를 이용해서 문자열을 만드는 방식을 말한다. 변수를 넣고자 할 때는 ${ 변수명 }, 이런 형태로 사용한다. 이것을 사용할 때의 가장 큰 장점은 직관성이다. 예전에는 변수와 문자열, 문자열과 문자열 등등 각 요소간의 결합은 + 를 이용하여 사용하였기 때문에 결합식이 길어질 경우 직관적이지 못했다. 하지만 template literals를 사용함으로서 훨씬 더 직관적이고 편하게 사용할 수 있게 되었다. 예를 들어 띄어쓰기나 줄바꿈의 경우 그대로 적용이 된다.

두번째는 reduce() 메소드이다. 지금까지 문제를 풀어올 때마다 많이 사용한 메소드로 다시 한 번 설명하면, 배열에서 하나의 (누적된) 결과값을 보여주고 싶을 때 사용한다. ( 참고. MDN reduce() )

세번째는 화살표함수(arrow function) 이다. 내가 잘 사용하지않는 구문이긴하다. 알고는 있는데 잘 사용이 안된다. 😥

  • 기본 구문

    ```javascript
    	(param1, param2, …, _paramN) => expression
    				// 다음과 동일함:  => { return expression } 
    	
    	// 매개변수가 하나뿐인 경우 괄호는 선택사항
    	(singleParam) => { statements }
    	 singleParam => { statements }
    
    	// 매개변수가 없는 함수는 괄호가 필요
    	() => { statements }
    	
    	//리턴값 표시
    	(...params) => 'return' 이라는 말 생략가능 : 바로 나온 코드가 리턴값이 된다.
    	(...params) => {
    		code here
    		'return' 이라는 말 생략을 못하고 명시적으로 적어줘야한다.
    	}
    ```

    arrow function을 사용하는 이유는 무엇일까? 이것도 코드가 직관적이고 간결해지기 때문에 사용한다. 하지만 아직 모든 곳에서 이 구문을 사용할수있는 것은 아니라고 한다. 작업환경(브라우저환경)에 따라서 적용이 안되는 곳도 있다고 한다.(특히 IE....) React를 처음 사용할 때 화살표함수를 정확히 사용할 줄 몰라서 애먹은적이 있었다. 보기에는 쉬워보여도 구문이 길어지면 어떻게 매개변수를 써야할지 혹은 리턴값은 어떻게 나타내는지 헷갈릴 수 있다. 익숙해져야 할 구문이다.

네번째는 ES6 문법은 아니지만 재치있는 코드인 +b 이다. 처음엔 왜 +를 넣은거지라는 의문이 들었다. 여러가지 실험을 해보니, +b는 b라는 문자(열)을 정수화시켜주기 위한 코드였다. 보통 정수화시킬 때는 Number()나 parseInt()를 많이 사용하는데 이렇게도 사용할 수 있다는 것을 처음 알게 되었다. 마치 문자열을 만들어주기 위해서 5+'' 와 같은 용도로 사용하였다.

결론

점차적으로 문제풀이를 함수형으로 풀어나가는데 익숙해지는 것 같다. 하지만 항상 생각해봐야 할 것은 한 줄로 간단하게 푼다고 해서 그것이 좋은 풀이는 아니라는 점이다. 항상 내 생각하는 바를 명확하고 간결하게 코드로서 나타내려고 노력하는 연습을 해야겠다. 어렵지않은 문제였지만 내가 의도한바를 코드로 표현하였다면, 그것만으로도 목표 달성이라고 생각한다.

참고

MDN Template literals
arrow_function의 장점은?
MDN 화살표 함수

🚀 문제를 풀어나갈 때 생각의 흐름을 정리합니다. 또한 새로운 풀이에 대한 코드를 분석하고 모르는 부분에 대해서 정리합니다. 생각이 다른 부분에 대한 피드백은 언제나 환영합니다. 틀린 내용에 대한 피드백 또한 항상 감사합니다.

profile
눈길을 걸어갈 때 어지럽게 걷지 말기를.

0개의 댓글