diff --git a/src/utils/june/groupBy.test.js b/src/utils/june/groupBy.test.js new file mode 100644 index 0000000..0653794 --- /dev/null +++ b/src/utils/june/groupBy.test.js @@ -0,0 +1,54 @@ +// FIXME: npm test /src/utils/groupBy.test.js + +const { _groupBy } = require('./util'); + +describe('groupBy 테스트', () => { + describe('non-lazy', () => { + it('case: 1, Normal', () => { + const array = [6.1, 4.2, 6.3]; + const grouped = _groupBy(array, Math.floor); + + expect(grouped).toEqual({ 4: [4.2], 6: [6.1, 6.3] }); + }); + + it('case: 2, Advanced', () => { + const array = [ + [1, 'a'], + [2, 'a'], + [2, 'b'], + ]; + + // 두 번째 인자가 index + const [groupedFirstIndex, groupedSecondIndex] = [ + _groupBy(array, item => item[0]), + _groupBy(array, item => item[1]), + ]; + + expect(groupedFirstIndex).toEqual({ + 1: [[1, 'a']], + 2: [ + [2, 'a'], + [2, 'b'], + ], + }); + + expect(groupedSecondIndex).toEqual({ + a: [ + [1, 'a'], + [2, 'a'], + ], + b: [[2, 'b']], + }); + }); + + it('case: 3, Advanced', () => { + const grouped = _groupBy({ a: 6.1, b: 4.2, c: 6.3 }, Math.floor); + + expect(grouped).toEqual({ 4: [4.2], 6: [6.1, 6.3] }); + }); + }); + + describe('lazy', () => { + // 여기에 Lazy 테스트 코드를 작성해보자!!! + }); +}); diff --git a/src/utils/june/juneTest.js b/src/utils/june/juneTest.js new file mode 100644 index 0000000..ef40f7e --- /dev/null +++ b/src/utils/june/juneTest.js @@ -0,0 +1,20 @@ +const { getMockData, timer } = require('../lib'); +const { pipe, map, filter, take } = require('./util'); + +const users = getMockData(); + +timer.start(); +const job = pipe( + map(user => user.age), + filter(age => age > 50), + take(2), +); +job(users); +timer.end(); + +timer.start(); +users + .map(user => user.age) + .filter(age => age > 50) + .slice(2); +timer.end(); diff --git a/src/utils/june/unique.test.js b/src/utils/june/unique.test.js new file mode 100644 index 0000000..e08a237 --- /dev/null +++ b/src/utils/june/unique.test.js @@ -0,0 +1,47 @@ +// FIXME: npm test /src/utils/unique.test.js +const { unique } = require('./util'); + +describe('unique 테스트', () => { + describe('non-lazy', () => { + it('case: 1, Normal', () => { + const [firstArray, secondArray] = [ + [2, 1, 2], + [1, 2, 1], + ]; + const firstUniqueArray = unique(firstArray); + const secondUniqueArray = unique(secondArray); + + expect(firstUniqueArray).toEqual([2, 1]); + expect(secondUniqueArray).toEqual([1, 2]); + }); + + it('case: 2, Advanced', () => { + const [firstArray, secondArray, thirdArray] = [ + [1, 2, 3], + [1, 1, 2, 2, 3], + [1, 2, 3, 3, 3, 3, 3], + ]; + const firstUniqueArray = unique(firstArray, undefined, true); + const secondUniqueArray = unique(secondArray, undefined, true); + const thirdUniqueArray = unique(thirdArray, undefined, true); + + expect(firstUniqueArray).toEqual([1, 2, 3]); + expect(secondUniqueArray).toEqual([1, 2, 3]); + expect(thirdUniqueArray).toEqual([1, 2, 3]); + }); + + it('case: 3, Advanced', () => { + const objects = [ + { x: 1, y: 2 }, + { x: 2, y: 1 }, + { x: 1, y: 2 }, + ]; + const uniqueObjects = unique(objects); + + expect(uniqueObjects).toEqual([ + { x: 1, y: 2 }, + { x: 2, y: 1 }, + ]); + }); + }); +}); diff --git a/src/utils/june/util.js b/src/utils/june/util.js new file mode 100644 index 0000000..daf2893 --- /dev/null +++ b/src/utils/june/util.js @@ -0,0 +1,85 @@ +const map = callback => { + return function* (iter) { + for (const item of iter) { + yield callback(item); + } + }; +}; + +const filter = callback => { + return function* (iter) { + for (const item of iter) { + if (callback(item)) yield item; + } + }; +}; + +const take = n => { + return function* (iter) { + let i = 0; + for (const item of iter) { + if (i >= n) return; + yield item; + i += 1; + } + }; +}; + +const pipe = + (...fns) => + iter => + fns.reduce((result, fn) => fn(result), iter); + +const _groupBy = (iter, fn) => { + const result = {}; + if (!iter[Symbol.iterator]) { + iter[Symbol.iterator] = function* () { + for (const key of Object.keys(iter)) yield iter[key]; + }; + } + for (const item of iter) { + const key = fn(item); + const values = result[key]; + result[key] = values ? [...values, item] : [item]; + } + return result; +}; + +const shallowEqual = (a, b) => { + for (const key of Object.keys(a)) { + if (a[key] !== b[key]) return false; + } + return true; +}; + +const unique = (arr, callback, isSorted) => { + const uniqueSet = new Set([]); + const newArr = [...arr]; + uniqueSet.add(newArr.shift()); + for (const item of newArr) { + const transformed = callback ? callback(item) : item; + const isObject = transformed !== null && typeof transformed === 'object'; + if (isObject) { + let included = false; + for (const value of uniqueSet.values()) { + if (shallowEqual(value, transformed)) included = true; + } + if (!included) uniqueSet.add(transformed); + } else { + if (!uniqueSet.has(transformed)) uniqueSet.add(transformed); + } + } + const result = Array.from(uniqueSet); + if (isSorted === false) result.sort((a, b) => a - b); + return result; +}; + +module.exports = { + map, + filter, + take, + pipe, + _groupBy, + unique, + shallowEqual, +};