[TIL] Day-29 Underbar

공부중인 개발자·2021년 5월 17일
0

TIL

목록 보기
29/64
post-thumbnail

알고리즘 구현하기

함수를 직접 구현해봤다. 테스트 케이스에서는 통과했지만 정확하다고는 할 수 없을 것 같다. 오늘 직접 구현해본 코드를 작성해본다.

_.identity

_.identity = function (val) {
  return val;
};

전달인자를 그대로 리턴해주는 함수

_.slice

_.slice = function (arr, start, end) {
  let _start = start || 0, // `start`가 undefined인 경우, slice는 0부터 동작합니다.
    _end = end;
  if (start < 0) _start = Math.max(0, arr.length + start);
  if (end < 0) _end = Math.max(0, arr.length + end);
  if (_end === undefined || _end > arr.length) _end = arr.length;
  let result = [];
  for (let i = _start; i < _end; i++) {
    result.push(arr[i]);
  }
  return result;
};

start 인덱스부터 end 인덱스 이전까지의 요소를 shallow copy하여 새로운 배열을 리턴

_.take

_.take = function (arr, n) {
  if(n < 0 || n === undefined) {
    return [];
  }
  return _.slice(arr, 0, n);
};

배열의 처음 n개의 element를 담은 새로운 배열을 리턴
n이 undefined이거나 음수인 경우, 빈 배열을 리턴
n이 배열의 길이를 벗어날 경우, 전체 배열을 shallow copy한 새로운 배열을 리턴

_.drop

_.drop = function (arr, n) {
  if(n < 0 || n === undefined) {
    return arr;
  }
  else if(n > arr.length) {
    return [];
  }
  else {
    return _.slice(arr, n, arr.length);
  }
};

처음 n개의 element를 제외한 새로운 배열을 리턴
n이 undefined이거나 음수인 경우, 전체 배열을 shallow copy한 새로운 배열을 리턴
n이 배열의 길이를 벗어날 경우, 빈 배열을 리턴

_.last

_.last = function (arr, n) {
  if(n === undefined || n < 0) {
    return _.slice(arr, -1);
  }
  else if(n > arr.length) {
    return _.take(arr, n);
  }
  else if(n === 0) {
    return [];
  }
  else {
    return _.slice(arr,-n);
  }
};

배열의 마지막 n개의 element를 담은 새로운 배열을 리턴
n이 undefined이거나 음수인 경우, 배열의 마지막 요소만을 담은 배열을 리턴
n이 배열의 길이를 벗어날 경우, 전체 배열을 shallow copy한 새로운 배열을 리턴

_.each

_.each = function (collection, iteratee) {
  if(Array.isArray(collection)) {
    for(let i = 0; i < collection.length; i++) {
      iteratee(collection[i], i, collection);
      }
    }
    else {
      for(let key in collection) {
        iteratee(collection[key], key, collection);
      }
    }
  };

collection의 각 데이터에 반복적인 작업을 수행

  1. collection(배열 혹은 객체)과 함수 iteratee(반복되는 작업)를 인자로 전달받아 (iteratee는 함수의 인자로 전달되는 함수이므로 callback 함수)
  2. collection의 데이터(element 또는 property)를 순회하면서
  3. iteratee에 각 데이터를 인자로 전달하여 실행

_.indexOf

_.indexOf = function (arr, target) {
  let result = -1;
  _.each(arr, function (item, index) {
    if (item === target && result === -1) {
      result = index;
    }
  });
  return result;
};

target으로 전달되는 값이 arr의 요소인 경우, 배열에서의 위치(index)를 리턴
그렇지 않은 경우, -1을 리턴
target이 중복해서 존재하는 경우, 가장 낮은 index를 리턴

_.filter

_.filter = function (arr, test) {
  let result = [];
  _.each(arr, function(el) {
    if(test(el)) {
      result.push(el);
    }
  })
  return result;
};

test 함수를 통과하는 모든 요소를 담은 새로운 배열을 리턴
test(element)의 결과(return 값)가 truthy일 경우, 통과
test 함수는 각 요소에 반복 적용

_.reject

_.reject = function (arr, test) {
  let result = [];
  _.each(arr, function(el) {
    if(!test(el)) {
      result.push(el);
    }
  })
  return result;
};

_.filter와 정반대로 test 함수를 통과하지 않는 모든 요소를 담은 새로운 배열을 리턴

_.uniq

_.uniq = function (arr) {
  let result = [];
  for(let el of arr) {
    if(_.indexOf(result, el) === -1) {
      result.push(el);
    }
  }
  return result;
};

주어진 배열의 요소가 중복되지 않도록 새로운 배열을 리턴
입력으로 전달되는 배열의 요소는 모두 primitive value라고 가정

_.map

_.map = function (arr, iteratee) {
  let result = [];
  _.each(arr, function(el) {
    result.push(iteratee(el));
  })
  return result;
};

iteratee(반복되는 작업)를 배열의 각 요소에 적용(apply)한 결과를 담은 새로운 배열을 리턴
배열의 각 요소를 다른 것(iteratee의 결과)으로 매핑(mapping)

_.pluck

_.pluck = function (arr, keyOrIdx) {
  let result = [];
  _.map(arr, function(el) {
    result.push(el[keyOrIdx]);
  })
  return result;
};
  1. 객체 또는 배열을 요소로 갖는 배열과 각 요소에서 찾고자 하는 key 또는 index를 입력받아
  2. 각 요소의 해당 값 또는 요소만을 추출하여 새로운 배열에 저장하고,
  3. 최종적으로 새로운 배열을 리턴

_.reduce

_.reduce = function (arr, iteratee, initVal) {
  if(initVal === undefined) {
    initVal = arr[0];
    _.each(_.slice(arr, 1), function(cur, idx, arr) {
      initVal = iteratee(initVal, cur, idx, arr);
    })
  }
  else {
    _.each(arr, function(cur, idx, arr) {
      initVal = iteratee(initVal, cur, idx, arr);
    })
  }
  return initVal;
};
  1. 배열을 순회하며 각 요소에 iteratee 함수를 적용하고,
  2. 그 결과값을 계속해서 누적(accumulate)합니다.
  3. 최종적으로 누적된 결과값을 리턴

_.once

_.once = function (func) {
  let checked = false;
  let result;
  return function () {
    if (!checked) {
      result = func(...arguments);
      checked = true;
    }
    return result;
  };
};

callback 함수를 한 번만 호출하는 '함수'를 리턴
여러 번 호출해도 callback 함수는 한 번 이상 호출되지 않는다.

_.delay

_.delay = function (func, wait, ...rest) {
  setTimeout(func, wait, ...rest)
};

입력으로 전달되는 시간(ms, 밀리초)후 callback 함수를 함께 전달되는 (임의의 개수의) 인자와 함께 실행

_.includes

_.includes = function (arr, target) {
  let result = false;
  _.each(arr, function(el) {
    if (el === target){
      result = true;
    }
  })
  return result;
};

배열이 주어진 값을 포함하는지 확인
입력으로 전달되는 배열의 요소는 모두 primitive value라고 가정

_.every

_.every = function (arr, iteratee) {
  let result = true;
  if (arr.length === 0) {
    return true;
  }
  if (iteratee === undefined) {
    for (let el of arr) {
      if(!el) {
        result = false;
        break;
      }
    }
  }
  else {
  for (let el of arr) {
    if (!iteratee(el)) {
      result = false;
      break;
    }
  }
}
  return result;
};

배열의 모든 요소가 test 함수(iteratee)를 통과하면 true를, 그렇지 않은 경우 false를 리턴
test(element)의 결과(return 값)가 truthy일 경우, 통과
빈 배열을 입력받은 경우, true를 리턴

_.some

_.some = function (arr, iteratee) {
  let result = false;
  if (arr.length === 0) {
    return false;
  }
  if (iteratee === undefined) {
    for (let el of arr) {
      if(el) {
        result = true;
        break;
      }
    }
  }
  else {
    for (let el of arr) {
      if(iteratee(el)) {
        result = true;
        break;
      }
    }
  }
  return result;
};

배열의 요소 중 하나라도 test 함수(iteratee)를 통과하면 true를, 그렇지 않은 경우 false를 리턴
빈 배열을 입력받은 경우, false를 리턴

_.extend

_.extend = function (...rest) {
  let result = rest[0];
  _.each(_.slice(rest,1), function(el) {
    for (let prop in el) {
      result[prop] = el[prop]
    }
  })
  return result;
};

여러 개의 객체를 입력받아, 순서대로 객체를 결합
첫 번째 입력인 객체를 기준으로 다음 순서의 객체들의 속성을 덮어씀
최종적으로 (속성이 추가된) 첫 번째 객체를 리턴 (새 객체 X)

_.defaults

_.defaults = function (...rest) {
  let result = rest[0];
  _.each(_.slice(rest,1), function(el) {
    for (let prop in el) {
      if (result[prop] === undefined) {
        result[prop] = el[prop]
      }
    }
  })
  return result;
};

_.extend와 비슷하게 동작하지만, 이미 존재하는 속성(key)을 덮어쓰지 않는다.

_.zip

_.zip = function (...rest) {
  let max =_.reduce(rest, (acc, cur) => acc.length > cur.length ? acc : cur).length;
  let result = [];
  _.each(rest, function (el) {
    for (let i = 0; i <max; i++) {
      if (result[i] === undefined) {
        result.push([])
      }
      result[i].push(el[i])
    }
  })
  return result;
};

여러 개의 배열을 입력받아, 같은 index의 요소들을 묶어 배열로 만들기
각 index 마다 하나의 배열을 만들고, 최종적으로 이 배열들을 요소로 갖는 배열을 리턴
최종적으로 리턴되는 배열의 각 요소의 길이는 입력으로 전달되는 배열 중 가장 '긴' 배열의 길이로 통일
특정 index에 요소가 없는 경우, undefined를 사용

_.zipStrict

_.zipStrict = function (...rest) {
  let min =_.reduce(rest, (acc, cur) => acc.length < cur.length ? acc : cur).length;
  let result = [];
  _.each(rest, function (el) {
    for (let i = 0; i <min; i++) {
      if (result[i] === undefined) {
        result.push([])
      }
      result[i].push(el[i])
    }
  })
  return result;
};

_.zip과 비슷하게 동작하지만,
최종적으로 리턴되는 배열의 각 요소의 길이는 입력으로 전달되는 배열 중 가장 '짧은' 배열의 길이로 통일


마지막으로...

코드 짤 때, 생각을 좀하면서 짜야겠다. 다 짜고나서 테스트를 통과했다고 무턱대고 넘어가지말고 좀 더 이해하기 쉽게 코드를 만들어야겠다.

profile
열심히 공부하자

0개의 댓글