2 분 소요

빈 배열에 추가, 삭제하기

문제 보기

문제

문제 설명

아무 원소도 들어있지 않은 빈 배열 X가 있습니다. 길이가 같은 정수 배열 arr과 boolean 배열 flag가 매개변수로 주어질 때, flag를 차례대로 순회하며 flag[i]가 true라면 X의 뒤에 arr[i]를 arr[i] x 2 번 추가하고, flag[i]가 false라면 X에서 마지막 arr[i]개의 원소를 제거한 뒤 X를 return 하는 solution 함수를 작성해 주세요.

풀이(일단은)

function solution(arr, flag) {
  const x = [];

  for (let i in flag) {
    if (flag[i]) {
      Array(arr[i])
        .fill()
        .forEach(() => {
          x.push(arr[i]);
          x.push(arr[i]);
        });
    } else {
      Array(arr[i])
        .fill()
        .forEach(() => x.pop());
    }
  }

  return x;
}

설명

이건 일단은 알고리즘을 자랑하려는 게 아니다. 더 편한 해법을 보여주고 싶어서 가져온 문제이다.

세상에는 내 문제를 이미 해결해 놓은 경우가 많다. 하늘 아래 새로울 것 없다고 하는데 코딩 세상에서는 특히 더 그렇다. 내가 고민하는 문제는 미안하지만, 다른 사람도 이미 고민했던 문제고 아마 여러분보다 더 뛰어난 사람들이 더 깔끔한 해법을 남겨놓았을 것이다. 아니라고? 그럼 지금 당장 논문을 써라. 논문이 부담된다면, 깃허브에 그 결과물을 올려라. 탑 티어 프로그래머로서 역사책에 이름을 남길 수 있을 것이다.

하여튼 이 문제도 그런 유형에 속한다. LoDash 라이브러리에는 zip()함수가 있는데 이 함수는 두 배열을 하나의 배열로 합치는 일을 한다. 그런데 합칠 때 pair라고 해야 하나? tuple이라고 해야 하나? 하여튼 원소의 짝으로 그룹화뢴 배열을 반환한다.

_.zip(["a", "b"], [1, 2], [true, false]);
// => [['a', 1, true], ['b', 2, false]]

우리의 문제에서는 두 개의 배열을 같은 인덱스로 참고하느라 forEach같은 걸 자유롭게 쓰질 못했다. 그렇다고 zip을 직접 구현하려니 번잡하다. 하려면 할 수도 있고 숏코딩에 자신있는 사람이라면 위의 해법보다 훨씬 짧게도 가능하겠지만 아쉽게도 내 머리는 zip 알고리즘을 기억해 줄 정도로 성능이 좋질 않다.

일단 해보자.

const _ = require("lodash");

const arr = [3, 2, 4, 1, 3];
const flag = [true, false, true, false, false];
const x = [];

const cmd = _.zip(arr, flag);

cmd.forEach(([el, flag]) => {
  if (flag) {
    [...Array(el * 2)].forEach(() => x.push(el));
  } else {
    [...Array(el)].forEach(() => x.pop());
  }
});

console.log(x);

데모 보기

[...Array(n)].forEach() 또는 [...Array(n)].map()은 이 문제를 푼 뒤에 배운 테크닉이다. 잔재주지만, 자바스크립트 세상에서는 잔재주를 쳐준다. 적어도 자바 세상보다는 더 쳐준다. 하는 일은 간단하다. n 만큼 반복하라.

하여튼 그게 중요한 게 아니고, zip을 사용함으로써 인텍스 참조가 사라져 코드가 깔끔해졌다. zip이 뭐하는 함수인지는 설명이 필요할 수도 있지만 zip을 안다고 가정할 수 있다면 나머지 코드의 가독성이 훨씬 올라간 것을 볼 수 있다.

그나저나 어떤 함수를 n번 반복 실행하는 고차 함수는 Lodash에 없나보다.

댓글남기기