Reverse words<7 kyu >

jjanmo·2019년 12월 28일
0

Codewars에서 뒹굴기

목록 보기
5/32

문제링크

문제

Complete the function that accepts a string parameter, and reverses each word in the string. All spaces in the string should be retained.

  • Examples
    "This is an example!" ==> "sihT si na !elpmaxe"
    "double spaces" ==> "elbuod secaps"

🎯 문제해석
간단하다. 주어진 문자열을 거꾸로 출력하시오.

문제접근

  • forEach()의 잘못된 사용
    문자열을 공백기준으로 나눈 후 그렇게 나온 배열을 통해서 해결하려고 하였다. 각각의 요소를 순회하며 무엇인가를 하고 싶을 때 (내가) 가장 먼저 생각하는 것은 forEach() 였다. 그런데 이것이 잘못된 만남이 되었다.
  const sample = "This is an example!";
  function reverseWords(str) {
    let strArr = str.split(' ')
    strArr.forEach(function(ele){
      ele = ele.split('').reverse().join('');
    });
   	return strArr.join(' ');
  }

 reverseWords(sample); //This is an example!

결과값을 콘솔에 찍어보면 집어넣었던 문자열이 동일하게 출력된다. 그렇다면 이 코드는 무엇이 잘못되었을까?? forEach()에 대한 정확한 이해가 선행되지 않았기 때문에 이런 실수가 나온 것이다. forEach()는 배열 안에서 무엇인가를 반복하여 수행하고자 할 때 주로 사용한다. 일반적으로 for문의 대체적인 느낌으로 사용한다. 여기서 중요한 점은 forEach()에는 리턴값이 없다는 것이다. 그 말은 원소마다 반복적으로 수행해서 새로운 배열을 만들고자 한다며 무엇인가를 더 추가해줘야 한다는 말이다. 즉, 반복적으로 수행한 결과를 새로운 변수에 넣어서 새 배열에 할당을 해주어야 반복 수행한 결과가 반영이 되는 것이다.

```javascript
1 	const sample = "This is an example!"; 			
2 	function reverseWords(str) {
3  	 let strArr = str.split(' ')
4  	 strArr.forEach(function(ele, idx){
5  	   ele = ele.split('').reverse().join('');
6      strArr[idx] = ele;
7 	});
8	 return strArr.join(' ');;
9	 }
10
11	reverseWords(sample); //sihT si na !elpmaxe
> 위에 코드뭉치와 다른 부분을 4,5,6번 라인이다. 변경된 값을 새로운 변수에 할당시켜준 부분이다. 같은 변수에만 할당했지 이것도 새로운 배열을 생성한 것과 마찬가지인 것이다. 그런데 이렇게 복잡하게 생각할 필요없이 **배열을 순회하면서 작업을 하고 그 작업한 결과를 배열로 만들어주는 메소드**가 이미 존재한다. 바로 **map()**이다. 배열을 순회한 후 결과값으로 새로운 배열이 만들어져야하는 상황이라면 forEach()보다 map()을 활용하는 것이 훨씬 좋은 선택인 것이다. 그런데 나같은 경우 뭔가 map()보다는 forEach()를 주로 사용하고 생각하는 경향이 있다. 아직 map()과 친해지지 않은 모양이다.
    
* map()을 생각하지 못한 자의 최후 
 
 ```javascript
  function reverseWords(str) {
    const strArr = str.split(' ');
    let newStr = '';
    for(let i = 0; i < strArr.length ; i++){
      for(let j = strArr[i].length; j >= 0; j--){
        newStr += strArr[i].charAt(j);
      }
      if(i !== strArr.length-1) newStr += ' ';
    }
    return newStr;
  }

실제로 제출한 코드이다. 이중 for문 안에서 문자열로 접근하여 charAt()을 이용하여 각각의 문자를 꺼내서 새로운 문자열 변수에 결합하는 것을 볼 수 있다.

Best Solution

function reverseWords(str) {
  return str.split(' ').map(function(word){
    return word.split('').reverse().join('');
  }).join(' ');
}

역시 좋은 풀이라고 적혀있는 것에는 map()을 사용하였다. 물론 reduce()를 사용하는 것도 있었다.

결론

항상 알로리즘, 코딩문제 등을 풀 때 궁금한 점이 생긴다. 어떤 풀이가 좋은 풀이인가 라는 것이다.

좋은 코드인지 아닌지를 알기위해선 누군가가 나의 코드를 보고 리뷰해준다면 그만큼 좋은 것이 없을 것이다. 프로그래밍을 배우는 입장에서 매번 누군가에게 자신의 코드들을 리뷰 받고 한다는 것은 매우 큰 행운이라고 생각한다. 그 말은 그런 경우가 많이 드물다는 것이다. 그렇기 때문에 나같은 경우 최대한 좋은 코드(오픈소스)를 찾아보고 비슷하게 코딩해보려고 노력을 한다.

이 문제를 보면 map()을 사용한 풀이, reduce()를 사용한 풀이, 나처럼 이중 for문을 돌려서 사용한 풀이 등등 다양한 풀이들이 존재한다. 여기서 어떤 풀이가 좋은 풀이일까? 개인적으로 나는 map()이나 reduce() 등, 메소드를 사용한 코딩이 좀 더 효율적인 코드라고 생각하고 내가 점차 익숙해져야하는 풀이라고 생각한다. 왜냐하면 아직 이런 풀이에 익숙하지않고 알고 있음에도 어떤 상황에서 어떻게 사용하는지를 정확하게 인지하지 못하고 있기 때문이다. 그런데 여기서 특정 메소드를 사용하는 것보다 직접 처음부터 구현해보는 것이 좋다 라고 말하는 사람도 있을 수 있다. 이 말도 맞다. '처음부터 구현한다'는 말은 메소드 기저에 있는 것들을 최대한 음미하면서 코딩을 해봐라라는 말인듯하다. 이렇게 구현을 하다보면 기본적으로 돌아가는 메커니즘에 대해서 생각하게 되고, 이를 알게 되면 다양한 상황들 속에서도 좀 더 명확하게 로직을 구현 할수 있는 능력이 생길 것이다. 모든 상황에서 메소드를 사용할 수 있는 건 아닐테니 말이다. 결론은 두 가지 모두 장점을 갖고 있으며 각각을 통해서 배울 수 있는 것들이 있다. 그렇기 때문에 두가지 방법 모두 상황에 맞게 여러 방면으로 지속적으로 사용하는 것이 좋은 개발자가 되기위해서 필요한 덕목이 아닐까 생각한다.

쓰고 보기까 한마디로 정리가 된다. 그냥 다 할 줄 알아야 한다!! 😅

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

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

0개의 댓글