들어가며

유튜브에서 놀다가 카카오 문제를 푸는 동영상이 있어서 대충 본 후에 갑자기 함수형 자바스크립트로 풀어보면 어떨까 하는 생각이 들었다. (관련 검색 리스트도 많네)

시간이 되는 대로 1번부터 7번까지 풀어봐야지.

일단 문제 출처는 여기.

1번 문제 풀이

var p1 = (n, arr1, arr2) => `["${Array.from({length: n}, v => 0)
  .map((_, i) => arr1[i] | arr2[i])
  .map(v => v.toString(2))
  .map(v => ('0'.repeat(n) + v).substr(-n))
  .map(v => v.replace(/1/g, '#'))
  .map(v => v.replace(/0/g, ' '))
  .join('", "')}"]`;

var n = 5
var arr1 = [9, 20, 28, 18, 11];
var arr2 = [30, 1, 21, 17, 28];
console.log(p1(n, arr1, arr2));
// ["#####", "# # #", "### #", "#  ##", "#####"]

var n = 6
var arr1 = [46, 33, 33 ,22, 31, 50];
var arr2 = [27 ,56, 19, 14, 14, 10];
console.log(p1(n ,arr1 , arr2));
// ["######", "###  #", "##  ##", " #### ", " #####", "### # "]

설명

0. 함수형 사고

  1. 배열 길이 n 배열 두개 arr1, arr2 를 입력받아서
  2. 결괏값을 저장할 n짜리 배열을 만들고
  3. 같은 인덱스인 애들끼리 or 연산을 하고,
  4. 2진수로 바꾸고,
  5. 바뀐 2진수의 자릿수를 n개까지 0으로 채우고,
  6. 1은 '#' 으로
  7. 0은 '  ' 으로 바꾸면 됨
  8. 마지막으로 join 을 이용하여 String 으로 변환~ (template literal 사용은 덤)

1. 일단 화살표 함수로 시작

var p1 = (n, arr1, arr2) => `...`;

문제의 정의대로 p1 은 인자 n, arr1, arr2 를 받아서 Array.from() 으로 생성된 배열을 map() 함수로 5번 가공 후 join()하여 Stringreturn 한다.

2. Array.from()

Array.from({length: n}, v => 0)

자바스크립트는 배열을 생성과 동시에 초기화까지 하는 구문이 없다. ES6에는 Array.from 구문이 있으니, 위와 같은 구문으로 0으로 초기화된 n 개짜리 배열을 만든다. (참고)

사실 위의 것은 좀 지적 허영심같고, 아래처럼 해도 된다.

'0'.repeat(n).split('')

뭐 어쨌든,

3. 1st map()

.map((_, i) => arr1[i] | arr2[i])

이 문제의 백미. bit연산인 or 를 하는 구문이다.

4. 2nd map()

.map(v => v.toString(2))

2진수로 바꾼다.

5. 3rd map()

.map(v => ('0'.repeat(n) + v).substr(-n))

문제의 설명에 보면

정수 배열의 각 원소 x를 이진수로 변환했을 때의 길이는 n 이하이다. 즉, 0 ≦ x ≦ 2^n - 1을 만족한다.

라는 내용이 있다. 즉, 2진수로 변환시 n자리 미만의 2진수가 나올 수 있다. 따라서 '0' 으로 lpadding해준다. (참고)

참고로 위의 방식을 사용하면

if (n < 10) return '00' + n;
else if (n < 100) return '0' + n;
else return n;

로 되어 있는 구문을

return ('000' + n).substr(-3)

한 줄로 줄일 수 있는 거다. 오호!

6. 4th map()

.map(v => v.replace(/1/g, '#'))

1은 '#' 으로

7. 5th map()

.map(v => v.replace(/0/g, ' '))

0은 공백('  ') 으로

8. join() with 템플릿 문자열

`["${[...].join('","')}"]`

7번까지 하면 결국 n개짜리 배열이 만들어지는데, 출력 형식을 맞추기 위하여 join('", "')을 해준다.
그리고 앞에는 [", 뒤에는 "]를 붙어주면 완성.
이것을 위해 template literals(템플릿 문자열)도 한번 써봤다.

사족 혹은 부심

사실 진짜 내가 생각하는 답은 여기.

// 아래 함수들은 Array.prototype.map 의 callback 으로 사용될 것임
const or = (arr1, arr2) => (_, i) => arr1[i] | arr2[i];
const bin = v => v.toString(2);
const lpad = n => v => ('0'.repeat(n) + v).substr(-n);
const repl = m => v => v.split('').map(v => m[v]).join('');

// 위에꺼 다 합치기
const arr = n => '0'.repeat(n).split('');
const rmap = { '0': ' ', '1': '#' };
const r = n => arr(n).map(or(arr1, arr2)).map(bin).map(lpad(n)).map(repl(rmap))

// 치장하는거
const j = (prefix, infix, postfix) => arr => `${prefix}${arr.join(infix)}${postfix}`;
const jjoin = j('["', '", "', '"]');

const p1 = (n, arr1, arr2) => jjoin(r(n));

더이상.jpg

함수형 프로그램은 짤 때는 참 기분이 좋은데, 다 짜놓고 읽어보면, 영 찝찝한 이 기분은 뭘까.

끝.