210825 TIL

코드아카데미 문제 풀이

Learn JavaScript Syntax: Iterators

반복자에 대한 기초적 지식을 공부한 후 문제 풀이

문제

워드 프로세싱 소프트웨어처럼 텍스트를 평가하고 개선하는 코드를 작성하세요.

  1. unnecessaryWords 배열 속 문자를 문자열story에 걸러내세요.

  2. console에 다음 항목을 출력하세요.

  • 문자열 story의 단어 수
  • 문자열 story의 문장 수
  • overusedWords배열이 문자열 story에 사용된 각 단어 수

할 일

  1. 문자열story를 개별 단어로 분할하고 storyWords이라는 새 배열에 저장한다.
  2. story 배열을 반복하여 unnecessaryWords 단어를 걸러낸 후 betterWords라는 배열에 나머지 단어를 저장한다.
  3. story에서 overusedWords 배열의 단어들을 얼마나 사용했는지 기록하기 위해 각 단어의 변수를 생성한다.
  4. story 배열을 반복하여 overusedWords 사용 수를 카운트시킨다.
  5. story의 문장 수를 계산하기 위해 . 또는 !로 끝나는 문자를 카운터 변수에 추가한다.
  6. 콘솔에 문제에서 요구한 항목을 출력한다.
  7. betterWords배열을 단일 문자열로 변경 후 콘솔에 출력한다.

문제 해결

1. story를 개별 단어로 분할하고 storyWords이라는 새 배열에 저장한다.

const storyWords = story.split(" ");

문자열을 개별 단어로 분리하고 배열을 반환하는 String.prototype.split 메서드를 사용했다. 이때 각 문자 모두 분리("")가 아닌 띄어쓰기로 단어를 개별 분리하기 때문에 (" ")를 인수로 전달했다.

2. unnecessaryWords 단어를 걸러낸 후 betterWords라는 배열에 나머지 단어를 저장한다.

const betterWords = storyWords.filter((storyWord) => {
  return !unnecessaryWords.includes(storyWord);
});

storyWords 배열 안에서는 unnecessaryWords가 중복으로 있을 수 있기 때문에 특정 요소 하나를 찾는 indexOf가 아닌 Array.prototype.filter 메서드를 사용했다.

왜 Array.prototype.includes를 사용했는가?
배열에 특정요소가 존재하는지 확인할 때 Array.prototype.indexOf 메서드와 Array.prototype.includes메서드가 있다. 여기서는 인덱스 반환보다 특정요소를 걸러내 새로운 배열을 담는 작업이 필요하기 때문에 true, false를 반환하는 Array.prototype.includes 메서드를 사용했다. 단, IE는 지원이 안된다고 한다.

3. overusedWords 배열의 각 단어의 변수를 생성하고 사용 수를 카운트시킨다.

let reallyCount = 0;
let veryCount = 0;
let basicallyCount = 0;

storyWords.forEach((storyWord) => {
  if (storyWord === "really") {
    return reallyCount++;
  } else if (storyWord === "very") {
    return veryCount++;
  } else if (storyWord === "basically") {
    return basicallyCount++;
  }
});

지금은 주어진 overusedWords가 3개만 있기 때문에 변수를 만들어 카운트하지만 만약 overusedWords가 기하급수적으로 많아진다면 이 방법은 비효율적인 것 같다.

count++; count += 1; count = count+1; 이들의 차이는 무엇일까?

  • ++ 단항 산술 연산자
  • += 할당 연산자
  • count += 1; count = count+1 동일 표현이다.
  • ++과 += 비교
    단항 산술 연살자 ++은 이 문제에서 피연산자 뒤에 위치한 후위증가 연사자다.
    즉, 먼저 다른 연산을 수행 후 피연산자 값을 증가시킨다.
    아래 실험을 보면 reallyCount++를 출력하면 콘솔출력을 먼저 실행한 후 피연산자 reallyCount 값이 증가된다. 그래서 콘솔창에는 값 변경없는 0이 출력되지만 실제 reallyCount 데이터 자체는 +1이 된 1 값을 가지고 있다. 그래서 다음 reallyCount 콘솔출력에는 증가된 1이 값으로 출력된다.

    할당연산자 +=는 우항에 있는 피연산자 평가 결과를 좌항에 있는 변수에 할당이 바로 적용된다.
    이 문제에서 += 1은 결국 reallyCount = reallyCount+1 과 동일 표현이기 때문에 값이 증가되고, 콘솔창에 변화된 실제 데이터 값 1이 그대로 출력된다.
  • +) 단항 산술연산자가 할당 연산자보다 연산자 우선순위가 높아 먼저 실행된다고 한다.

처음 코드를 작성했을 때 return reallyCount += 1;이 아닌 return reallyCount++; 으로 작성을 해도 왜 reallyCount 값은 둘 다 정상적으로 2가 출력되는지 이해가 가지 않았다.
코드를 계속 보다가 forEach 메서드는 undefined만을 반환하기 때문에 if문의 return 키워드는 필요가 없다는 사실을 깨달았다. 즉, return여부와 상관없이 내가 생각했던 reallyCount++의 값이 아닌 최종 reallyCount값이 저장되기 때문에 2가 반환된 것이다.

5. story의 . 또는 !로 끝나는 문자를 카운터 변수에 추가한다.

let sentencesCount = 0;

betterWords.forEach((betterWord) => {
  if (
    betterWord[betterWord.length - 1] === "." ||
    betterWord[betterWord.length - 1] === "!"
  ) {
    return sentencesCount++;
  }
}); 

betterWords는 배열로 이터러블이다. 그래서 위의 forEach를 아래의 for...of으로 바꿀 수 있다.

let sentencesCount = 0;
for (const betterWord of betterWords) {
  if (
    betterWord[betterWord.length - 1] === "." ||
    betterWord[betterWord.length - 1] === "!"
  ) {
    sentencesCount++;
  }
}
  • forEach와 달리 for...of는 continue와 break 사용해 루프를 제어할 수 있고 return을 사용해 반환할수도 있다.

6. 콘솔에 문제에서 요구한 항목을 출력한다.

console.log(`단어수: ${betterWords.length}`);
console.log(`문장수: ${sentencesCount}`);
console.log(`really 단어 수: ${reallyCount}`);
console.log(`very 단어 수: ${veryCount}`);
console.log(`basically 단어 수: ${basicallyCount}`);

7. betterWords배열을 단일 문자열로 변경 후 콘솔에 출력한다.

console.log(betterWords.join(" "));

Array.prototype.join 메서드는 배열의 모든 요소를 문자열로 변환 후 인수로 전달받은 구분자로 연결한 문자열을 반환한다. 여기서 betterWords에 있는 모든 요소를 split하기 전 상태로 돌리기 위해 띄어쓰기(" ")를 인수로 넣었다.

전체코드

let story =
  'Last weekend, I took literally the most beautiful bike ride of my life. The route is called "The 9W to Nyack" and it actually stretches all the way from Riverside Park in Manhattan to South Nyack, New Jersey. It\'s really an adventure from beginning to end! It is a 48 mile loop and it basically took me an entire day. I stopped at Riverbank State Park to take some extremely artsy photos. It was a short stop, though, because I had a really long way left to go. After a quick photo op at the very popular Little Red Lighthouse, I began my trek across the George Washington Bridge into New Jersey.  The GW is actually very long - 4,760 feet! I was already very tired by the time I got to the other side.  An hour later, I reached Greenbrook Nature Sanctuary, an extremely beautiful park along the coast of the Hudson.  Something that was very surprising to me was that near the end of the route you actually cross back into New York! At this point, you are very close to the end.';
let overusedWords = ["really", "very", "basically"];
let unnecessaryWords = ["extremely", "literally", "actually"];

/* Task 1 */
const storyWords = story.split(" ");

/* Task2*/
console.log(storyWords.length);

/* Task3 */
const betterWords = storyWords.filter((storyWord) => {
  return !unnecessaryWords.includes(storyWord);
});

/* Task4 */
let reallyCount = 0;
let veryCount = 0;
let basicallyCount = 0;

storyWords.forEach((storyWord) => {
  if (storyWord === "really") {
    reallyCount++;
  } else if (storyWord === "very") {
    veryCount++;
  } else if (storyWord === "basically") {
    basicallyCount++;
  }
});

/* Task 5*/
let sentencesCount = 0;
betterWords.forEach((betterWord) => {
  if (
    betterWord[betterWord.length - 1] === "." ||
    betterWord[betterWord.length - 1] === "!"
  ) {
    sentencesCount++;
  }
});

/* Task 6*/
console.log(`단어수: ${betterWords.length}`);
console.log(`문장수: ${sentencesCount}`);
console.log(`really 단어 수: ${reallyCount}`);
console.log(`very 단어 수: ${veryCount}`);
console.log(`basically 단어 수: ${basicallyCount}`);

/* Task 7 */
console.log(betterWords.join(" "));

+) 기타

Array.from에 관한 자료를 보다가 콜백함수의 매개변수에 _언더바를 발견했다.

Array.from({length: 5}, (_, i) => i);
// [0, 1, 2, 3, 4]
  • 찾아보니 언더바는 해당 매개변수를 신경 쓰지 않겠다는 의미를 담고 있다. 위의 예제에선 언더바가 아닌 e, f, a 등 아무 이름을 넣어 출력해도 똑같이 배열의 요소값으로 undefined 을 갖는데 e, f, a는 아무런 의미가 없는 이름이기 때문에 올바르지 않다. 그래서 해당 매개변수를 신경 쓰지 않아도 된다는 의미를 암시해줄 _언더바를 쓰는 것이었다.
  • 매개변수에 ( )빈 괄호를 써도 되지만 언더바는 타이핑이 한 번이고 괄호는 두 번이라 언더바를 쓴다 고도한다.
  • 하스켈의 와일드 카드 패턴으로 _ 언더바는 anyting아무거나를 의미한다고도 한다.

좋은 웹페이지 즐겨찾기