diff --git "a/\354\240\225\354\227\260\354\261\204/ex1/book-edit.html" "b/\354\240\225\354\227\260\354\261\204/ex1/book-edit.html" index e69de29..2367f71 100644 --- "a/\354\240\225\354\227\260\354\261\204/ex1/book-edit.html" +++ "b/\354\240\225\354\227\260\354\261\204/ex1/book-edit.html" @@ -0,0 +1,68 @@ + + + + + + Bookmark Edit + + + + + +
+

+ BookMark Logo + BookMark +

+ +
+ +
+
+
+
+
+ +
+
+ + +
+ +
+
+ Undo Icon +
+
+ Save Icon +
+
+
+ +

There is no marks.

+
+
+ +
+ + + + + + diff --git "a/\354\240\225\354\227\260\354\261\204/ex1/book.png" "b/\354\240\225\354\227\260\354\261\204/ex1/book.png" new file mode 100644 index 0000000..dfd09d0 Binary files /dev/null and "b/\354\240\225\354\227\260\354\261\204/ex1/book.png" differ diff --git "a/\354\240\225\354\227\260\354\261\204/ex1/bookmark_logo.png" "b/\354\240\225\354\227\260\354\261\204/ex1/bookmark_logo.png" new file mode 100644 index 0000000..43406c3 Binary files /dev/null and "b/\354\240\225\354\227\260\354\261\204/ex1/bookmark_logo.png" differ diff --git "a/\354\240\225\354\227\260\354\261\204/ex1/index.html" "b/\354\240\225\354\227\260\354\261\204/ex1/index.html" index e69de29..6c7d351 100644 --- "a/\354\240\225\354\227\260\354\261\204/ex1/index.html" +++ "b/\354\240\225\354\227\260\354\261\204/ex1/index.html" @@ -0,0 +1,144 @@ + + + + + + + Home Page + + + + + + +
+
+ BookMark Logo +

BookMark

+
+ +
+ +
+ + + + +
+

Study

+
+
+
+ Study +
+ Tailwind CSS +

Tailwind CSS is a utility-first CSS framework

+
+
+ +
+ +
+ +
+
+
+
+ + + + + diff --git "a/\354\240\225\354\227\260\354\261\204/ex1/index2.html" "b/\354\240\225\354\227\260\354\261\204/ex1/index2.html" new file mode 100644 index 0000000..1f22b40 --- /dev/null +++ "b/\354\240\225\354\227\260\354\261\204/ex1/index2.html" @@ -0,0 +1,142 @@ + + + + + + + Home Page + + + + + + + +
+
+ BookMark Logo +

BookMark

+
+ +
+ + +
+ + + + +
+

Study

+
+ +
+
+ Study +
+ Tailwind CSS +

Tailwind CSS is a utility-first CSS framework

+
+
+ +
+ +
+ +
+
+
+
+ + + diff --git "a/\354\240\225\354\227\260\354\261\204/ex1/kakao.png" "b/\354\240\225\354\227\260\354\261\204/ex1/kakao.png" new file mode 100644 index 0000000..d802ab5 Binary files /dev/null and "b/\354\240\225\354\227\260\354\261\204/ex1/kakao.png" differ diff --git "a/\354\240\225\354\227\260\354\261\204/ex1/naver.png" "b/\354\240\225\354\227\260\354\261\204/ex1/naver.png" new file mode 100644 index 0000000..00686ea Binary files /dev/null and "b/\354\240\225\354\227\260\354\261\204/ex1/naver.png" differ diff --git "a/\354\240\225\354\227\260\354\261\204/ex1/profile.png" "b/\354\240\225\354\227\260\354\261\204/ex1/profile.png" new file mode 100644 index 0000000..8bc7c79 Binary files /dev/null and "b/\354\240\225\354\227\260\354\261\204/ex1/profile.png" differ diff --git "a/\354\240\225\354\227\260\354\261\204/ex1/register.html" "b/\354\240\225\354\227\260\354\261\204/ex1/register.html" index e69de29..eeb34d5 100644 --- "a/\354\240\225\354\227\260\354\261\204/ex1/register.html" +++ "b/\354\240\225\354\227\260\354\261\204/ex1/register.html" @@ -0,0 +1,57 @@ + + + + + + Register + + + + +
+
+ BookMark Logo +

BookMark

+
+
+ + +
+
+
+

Sign Up

+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+
+ + + + diff --git "a/\354\240\225\354\227\260\354\261\204/ex1/save.png" "b/\354\240\225\354\227\260\354\261\204/ex1/save.png" new file mode 100644 index 0000000..04df82c Binary files /dev/null and "b/\354\240\225\354\227\260\354\261\204/ex1/save.png" differ diff --git "a/\354\240\225\354\227\260\354\261\204/ex1/save2.png" "b/\354\240\225\354\227\260\354\261\204/ex1/save2.png" new file mode 100644 index 0000000..8dc320c Binary files /dev/null and "b/\354\240\225\354\227\260\354\261\204/ex1/save2.png" differ diff --git "a/\354\240\225\354\227\260\354\261\204/ex1/setting.png" "b/\354\240\225\354\227\260\354\261\204/ex1/setting.png" new file mode 100644 index 0000000..845c81d Binary files /dev/null and "b/\354\240\225\354\227\260\354\261\204/ex1/setting.png" differ diff --git "a/\354\240\225\354\227\260\354\261\204/ex1/tailwind.png" "b/\354\240\225\354\227\260\354\261\204/ex1/tailwind.png" new file mode 100644 index 0000000..7d158f2 Binary files /dev/null and "b/\354\240\225\354\227\260\354\261\204/ex1/tailwind.png" differ diff --git "a/\354\240\225\354\227\260\354\261\204/ex1/undo.png" "b/\354\240\225\354\227\260\354\261\204/ex1/undo.png" new file mode 100644 index 0000000..923cc05 Binary files /dev/null and "b/\354\240\225\354\227\260\354\261\204/ex1/undo.png" differ diff --git "a/\354\240\225\354\227\260\354\261\204/ex1/youtube.png" "b/\354\240\225\354\227\260\354\261\204/ex1/youtube.png" new file mode 100644 index 0000000..7d2736f Binary files /dev/null and "b/\354\240\225\354\227\260\354\261\204/ex1/youtube.png" differ diff --git "a/\354\240\225\354\227\260\354\261\204/ex10.test.ts" "b/\354\240\225\354\227\260\354\261\204/ex10.test.ts" index 6218a79..19d585b 100644 --- "a/\354\240\225\354\227\260\354\261\204/ex10.test.ts" +++ "b/\354\240\225\354\227\260\354\261\204/ex10.test.ts" @@ -1,4 +1,98 @@ import { ArrayList } from './ex10'; +import assert from 'assert'; + console.log('🚀 ArrayList:', ArrayList); -// 여기에 테스트코드를 작성하세요. +console.log(ArrayList.listToArray({ value: 1, rest: { value: 2, rest: null } })); +console.log(ArrayList.arrayToList([1, 2])); + +const alist = new ArrayList([1, 2]); +console.log(alist.toString()); +alist.add(3); +console.log(alist.toString()); +alist.add(5, 1); +console.log(alist.toString()); +alist.remove(2); +console.log(alist.toString()); +alist.add(22, 1); +console.log(alist.toString()); +alist.add(33, 1); +console.log(alist.toString()); +alist.set(1, 300); +console.log(alist.toString()); +console.log(alist.get(2)); +console.log(alist.size()); +console.log(alist.indexOf(300)); +console.log(alist.contains(300)); +console.log(alist.contains(301)); +console.log(alist.isEmpty()); +console.log(alist.peek()); +console.log(alist.toArray()); +console.log(alist.iterator().next()); +alist.clear(); +console.log(alist.toString()); + + +// const alist = new ArrayList([1, 2]); +// console.log('list:', alist.toString()); + +// alist.add(8); // [4, 7, 8] +// alist.add(15, 1); // [4, 15, 7, 8] +// assert.deepStrictEqual(alist.toArray(), [4, 15, 7, 8], 'add() 실패'); + +// alist.add(25, 2); // [4, 15, 25, 7, 8] +// alist.add(40, 0); // [40, 4, 15, 25, 7, 8] +// assert.deepStrictEqual(alist.toArray(), [40, 4, 15, 25, 7, 8], 'add() with index 실패'); + +// // const removedValue = alist.removeByIndex(1); // [40, 15, 25, 7, 8] +// // assert.strictEqual(removedValue, 4, 'removeByIndex 실패'); +// // assert.deepStrictEqual(alist.toArray(), [40, 15, 25, 7, 8], 'removeByIndex 실패'); + +// // const removedResult = alist.removeValue(25); // [40, 15, 7, 8] +// // assert.strictEqual(removedResult, true, 'removeValue 실패'); +// // assert.deepStrictEqual(alist.toArray(), [40, 15, 7, 8], 'removeValue 실패'); + +// const failedRemove = alist.remove(100); // 값이 없으므로 false +// assert.strictEqual(failedRemove, false, 'removeValue 실패 2'); + +// assert.strictEqual(alist.get(0), 40, 'get() 실패'); +// assert.strictEqual(alist.get(2), 7, 'get() 실패'); +// assert.strictEqual(alist.get(10), undefined, 'get() 실패 2'); + +// alist.set(1, 350); // [40, 350, 7, 8] +// assert.deepStrictEqual(alist.toArray(), [40, 350, 7, 8], 'set() 실패'); + +// assert.strictEqual(alist.contains(350), true, 'contains() 실패'); +// assert.strictEqual(alist.contains(301), false, 'contains() 실패'); + +// assert.strictEqual(alist.indexOf(350), 1, 'indexOf() 실패'); +// assert.strictEqual(alist.indexOf(500), -1, 'indexOf() 실패'); + +// assert.strictEqual(alist.size(), 4, 'size() 실패'); + +// assert.strictEqual(alist.isEmpty, false, 'isEmpty() 실패'); +// alist.clear(); +// assert.strictEqual(alist.isEmpty, true, 'isEmpty() 실패2'); + +// alist.add(45); +// alist.add(55); +// alist.add(65); +// const iterator = alist.iterator(); + +// const firstIter = iterator.next(); +// assert.deepStrictEqual(firstIter.value, 65, 'iterator() 1 실패'); +// assert.strictEqual(firstIter.done, false, 'iterator() 1 done 실패'); + +// const secondIter = iterator.next(); +// assert.deepStrictEqual(secondIter.value, 55, 'iterator() 2 실패'); +// assert.strictEqual(secondIter.done, false, 'iterator() 2 done 실패'); + +// const thirdIter = iterator.next(); +// assert.deepStrictEqual(thirdIter.value, 45, 'iterator() 3 실패'); +// assert.strictEqual(thirdIter.done, false, 'iterator() 3 done 실패'); + +// const fourthIter = iterator.next(); +// assert.strictEqual(fourthIter.value, undefined, 'iterator() 4 실패'); +// assert.strictEqual(fourthIter.done, true, 'iterator() 실패'); + +// assert.deepStrictEqual(alist.toArray(), [45, 55, 65], 'toArray() 실패'); \ No newline at end of file diff --git "a/\354\240\225\354\227\260\354\261\204/ex10.ts" "b/\354\240\225\354\227\260\354\261\204/ex10.ts" index 1ffaef5..a35e855 100644 --- "a/\354\240\225\354\227\260\354\261\204/ex10.ts" +++ "b/\354\240\225\354\227\260\354\261\204/ex10.ts" @@ -1,71 +1,318 @@ -class Collection { - private readonly arr = Array(); +// class Collection { +// private readonly arr = Array(); - constructor(...args: T[]) { - this.arr.push(...args); +// constructor(...args: T[]) { +// this.arr.push(...args); +// } + +// get _arr() { +// return this.arr; +// } + +// push(...args: T[]) { +// this.arr.push(...args); +// return this.arr; +// } + +// get peek(): T | undefined { +// return this.isQueue() ? this.arr[0] : this.arr.at(-1); +// } + +// get poll(): T | undefined { +// return this.isQueue() ? this.arr.shift() : this.arr.pop(); +// } + +// remove() { +// return this.poll; +// } + +// get length() { +// return this.arr.length; +// } + +// get isEmpty() { +// return !this.arr.length; +// } + +// clear() { +// this.arr.length = 0; +// } + +// iterator() { +// return this[Symbol.iterator](); +// } + +// // [1, 2, 3] +// *[Symbol.iterator]() { +// for (let i = this.length - 1; i >= 0; i -= 1) { +// yield this.toArray()[i]; +// } +// } + +// toArray() { +// return this.isQueue() ? this.arr.toReversed() : this.arr; +// } + +// print() { +// console.log(`<${this.constructor.name}: [${this.toArray()}]>`); +// } + +// private isQueue() { +// return this instanceof Queue; +// } +// } + +// class Stack extends Collection {} +// class Queue extends Collection {} + +// // ArrayList 클래스를 작성하세요. +// class ArrayList extends Collection { +// constructor(...args: T[]) { +// super(...args); +// } + +// add(value: T, index?: number): void { +// if (index === undefined) { +// this._arr.push(value); +// } else { +// this._arr.splice(index, 0, value); +// } +// } + +// get(index: number): T | undefined { +// return this._arr[index]; +// } + +// removeValue(value: T): boolean { +// const index = this.indexOf(value); +// if (index !== -1) { +// this._arr.splice(index, 1); +// return true; +// } +// return false; +// } + +// removeByIndex(index: number): T | undefined { +// if (index >= 0 && index < this.length) { +// return this._arr.splice(index, 1)[0]; +// } +// return undefined; +// } + +// set(index: number, value: T): void { +// if (index >= 0 && index < this.length) { +// this._arr[index] = value; +// } +// } + +// contains(value: T): boolean { +// return this._arr.includes(value); +// } + +// indexOf(value: T): number { +// return this._arr.indexOf(value); +// } + +// size(): number { +// return this.length; +// } + +// toArray(): T[] { +// return [...this._arr]; +// } + +// toString(): string { +// return `ArrayList(${this.size()}) { ${this._arr.map((v) => `value: ${v}`).join(', ')} }`; +// } +// } + +// export { Stack, Queue, ArrayList }; + +/********************************************************************************************************************** */ +interface Collection { + add(value: T, index?: number): void; + remove(index: number): void; + clear(): void; + contains(value: T): boolean; + size(): number; + isEmpty(): boolean; + toArray(): T[]; + iterator(): Iterator; +} + +interface ListNode { + value: T; + rest: ListNode | null; +} + +class ArrayList implements Collection { + private head: ListNode | null = null; + private length: number = 0; + + constructor(array: T[] = []) { + this.clear(); + if (Array.isArray(array)) { + array.forEach((item) => this.add(item)); + } } - get _arr() { - return this.arr; + clear(): void { + this.head = null; + this.length = 0; + } + + add(value: T, index: number = this.size()): void { + if (index < 0 || index > this.size()) throw new Error('Index out of bounds'); + + const newNode: ListNode = { value, rest: null }; + + if (index === 0) { + newNode.rest = this.head; + this.head = newNode; + } else { + const prevNode = this._getNode(index - 1); + newNode.rest = prevNode.rest; + prevNode.rest = newNode; + } + + this.length++; } - push(...args: T[]) { - this.arr.push(...args); - return this.arr; + remove(index: number): void { + if (index < 0 || index >= this.size()) throw new Error('Index out of bounds'); + + if (index === 0) { + this.head = this.head!.rest; + } else { + const prevNode = this._getNode(index - 1); + prevNode.rest = prevNode.rest!.rest; + } + + this.length--; } - get peek(): T | undefined { - return this.isQueue() ? this.arr[0] : this.arr.at(-1); + set(index: number, value: T): void { + const node = this._getNode(index); + node.value = value; } - get poll(): T | undefined { - return this.isQueue() ? this.arr.shift() : this.arr.pop(); + get(index: number): T { + return this._getNode(index).value; } - remove() { - return this.poll; + contains(value: T): boolean { + return this.indexOf(value) !== -1; } - get length() { - return this.arr.length; + indexOf(value: T): number { + let currentNode = this.head; + let index = 0; + while (currentNode) { + if (currentNode.value === value) return index; + currentNode = currentNode.rest; + index++; + } + return -1; } - get isEmpty() { - return !this.arr.length; + peek(): T | undefined { + if (!this.head) return undefined; + return this.head.value; } - clear() { - this.arr.length = 0; + size(): number { + return this.length; } - iterator() { - return this[Symbol.iterator](); + isEmpty(): boolean { + return this.size() === 0; } - // [1, 2, 3] - *[Symbol.iterator]() { - for (let i = this.length - 1; i >= 0; i -= 1) { - yield this.toArray()[i]; + toArray(): T[] { + const result: T[] = []; + let currentNode = this.head; + while (currentNode) { + result.push(currentNode.value); + currentNode = currentNode.rest; } + return result; } - toArray() { - return this.isQueue() ? this.arr.toReversed() : this.arr; + toString(): string { + return `ArrayList(${this.size()}) ${JSON.stringify(this.head)}`; } - print() { - console.log(`<${this.constructor.name}: [${this.toArray()}]>`); + iterator(): Iterator { + let currentNode = this.head; + return { + next: (): IteratorResult => { + if (!currentNode) { + return { value: undefined, done: true }; + } + const value = currentNode.value; + currentNode = currentNode.rest; + return { value, done: false }; + } + }; } - private isQueue() { - return this instanceof Queue; + private _getNode(index: number): ListNode { + if (index < 0 || index >= this.size()) throw new Error('Index out of bounds'); + let currentNode = this.head; + for (let i = 0; i < index; i++) { + currentNode = currentNode!.rest; + } + return currentNode!; + } + + static listToArray(list: ListNode | null): T[] { + const array: T[] = []; + let current = list; + while (current) { + array.push(current.value); + current = current.rest; + } + return array; + } + + static arrayToList(array: T[]): ListNode | null { + let head: ListNode | null = null; + for (let i = array.length - 1; i >= 0; i--) { + head = { value: array[i], rest: head }; + } + return head; } } -class Stack extends Collection {} -class Queue extends Collection {} +export {ArrayList }; + +// console.log(ArrayList.listToArray({ value: 1, rest: { value: 2, rest: null } })); //⇒ [1,2] +// console.log(ArrayList.arrayToList([1, 2])); //⇒ { value: 1, rest: { value: 2, rest: null } } + +// const alist = new ArrayList([1, 2]); +// console.log(alist.toString()); +// alist.add(3); +// console.log(alist.toString()); +// alist.add(5, 1); +// console.log(alist.toString()); +// alist.remove(2); +// console.log(alist.toString()); +// alist.add(22, 1); +// console.log(alist.toString()); +// alist.add(33, 1); +// console.log(alist.toString()); +// alist.set(1, 300); +// console.log(alist.toString()); +// console.log(alist.get(2)); +// console.log(alist.size()); +// console.log(alist.indexOf(300)); +// console.log(alist.contains(300)); +// console.log(alist.contains(301)); +// console.log(alist.isEmpty()); +// console.log(alist.peek()); +// console.log(alist.toArray()); +// console.log(alist.iterator().next()); +// alist.clear(); +// console.log(alist.toString()); -// ArrayList 클래스를 작성하세요. -class ArrayList extends Collection {} -export { Stack, Queue, ArrayList }; diff --git "a/\354\240\225\354\227\260\354\261\204/ex2.js" "b/\354\240\225\354\227\260\354\261\204/ex2.js" index 6b95f04..be51e17 100644 --- "a/\354\240\225\354\227\260\354\261\204/ex2.js" +++ "b/\354\240\225\354\227\260\354\261\204/ex2.js" @@ -1,4 +1,34 @@ -// range 함수를 작성하세요. -const range = (start, end, step = start > end ? -1 : 1) => { }; +const range = (start, end, step = start > end ? -1 : 1) => { + let result = []; + + const add = (a, b) => { + return parseFloat((a + b).toFixed(10)); + }; -module.exports = { range }; + if (end === undefined) { + if (start === 0) + return [0]; + + if (start > 0) { + end = start; + start = 1; + } else { + end = -1; + } + } + + if (step === 0) + return [start]; + + if ((start > end && step > 0) || (start < end && step < 0)) { + return result; + } + + for (let i = start; step > 0 ? i <= end : i >= end; i = add(i, step)) { + result.push(i); + } + + return result; + }; + + module.exports = { range }; \ No newline at end of file diff --git "a/\354\240\225\354\227\260\354\261\204/ex3.js" "b/\354\240\225\354\227\260\354\261\204/ex3.js" index b1b0d75..36c57f1 100644 --- "a/\354\240\225\354\227\260\354\261\204/ex3.js" +++ "b/\354\240\225\354\227\260\354\261\204/ex3.js" @@ -1,3 +1,26 @@ Array.prototype.sortBy = function (sortProp = '') { - return this; -}; + + const str = sortProp.split(',').map(s => { + const [key, order] = s.split(':'); + return { + key: key.trim(), + order: (order && order.trim().toLowerCase()) === 'desc' ? -1 : 1 + }; + }); + + const compare = (a, b, key, order) => { + if (a[key] > b[key]) return order; + if (a[key] < b[key]) return (-1) * order; + return 0; + }; + + return this.sort((a, b) => { + return str.reduce((result, { key, order }) => { + + if (result !== 0) + return result; + + return compare(a, b, key, order); + }, 0); + }); +}; \ No newline at end of file diff --git "a/\354\240\225\354\227\260\354\261\204/ex3.test.js" "b/\354\240\225\354\227\260\354\261\204/ex3.test.js" index 6c27a4d..1628e15 100644 --- "a/\354\240\225\354\227\260\354\261\204/ex3.test.js" +++ "b/\354\240\225\354\227\260\354\261\204/ex3.test.js" @@ -8,11 +8,11 @@ const users = [lee, hong, kim]; assert.deepStrictEqual(users.sortBy('id'), [hong, kim, lee]); assert.deepStrictEqual(users.sortBy('name:desc'), [lee, kim, hong]); -assert.deepStrictEqual(users.sortBy('dept:desc,city:asc'), [hong, lee, kim]); +assert.deepStrictEqual(users.sortBy('dept:desc,city:asc'), [lee, kim, hong]); assert.deepStrictEqual(users.sortBy('dept:desc,city:desc'), [kim, lee, hong]); assert.deepStrictEqual(users.sortBy('name:desc,id:,dept:desc'), [ - kim, lee, + kim, hong, ]); -assert.deepStrictEqual(users.sortBy('dept:desc,id'), [hong, kim, lee]); +assert.deepStrictEqual(users.sortBy('dept:desc,id'), [kim, lee, hong]); diff --git "a/\354\240\225\354\227\260\354\261\204/ex4.js" "b/\354\240\225\354\227\260\354\261\204/ex4.js" index 9ede02f..13a52cd 100644 --- "a/\354\240\225\354\227\260\354\261\204/ex4.js" +++ "b/\354\240\225\354\227\260\354\261\204/ex4.js" @@ -1,3 +1,61 @@ -function deepCopy(obj) {} +function objectCopy(obj, wm) { + const objCopy = Object.create(Object.getPrototypeOf(obj)); + wm.set(obj, objCopy); + + + Object.getOwnPropertyNames(obj).forEach((key) => { + objCopy[key] = deepCopy(obj[key], wm); + }); + + Object.getOwnPropertySymbols(obj).forEach((sym) => { + objCopy[sym] = deepCopy(obj[sym], wm); + }); + + return objCopy; +} + +function arrayCopy(arr, wm) { + const arrCopy = []; + wm.set(arr, arrCopy); + arr.forEach((item, index) => { + arrCopy[index] = deepCopy(item, wm); + }); + return arrCopy; +} + +function setCopy(set, wm) { + const setCopy = new Set(); + wm.set(set, setCopy); + set.forEach((value) => { + setCopy.add(deepCopy(value, wm)); + }); + return setCopy; +} + +function mapCopy(map, wm) { + const mapCopy = new Map(); + wm.set(map, mapCopy); + map.forEach((value, key) => { + mapCopy.set(deepCopy(key, wm), deepCopy(value, wm)); + }); + return mapCopy; +} + +function deepCopy(obj, wm = new WeakMap()) { + if (obj === null || typeof obj !== "object") return obj; + + if (wm.has(obj)) return wm.get(obj); + + if (Array.isArray(obj)) + return arrayCopy(obj, wm); + if (obj instanceof Set) + return setCopy(obj, wm); + if (obj instanceof Map) + return mapCopy(obj, wm); + if (obj instanceof WeakSet || obj instanceof WeakMap) + return obj; + + return objectCopy(obj, wm); +} module.exports = { deepCopy }; diff --git "a/\354\240\225\354\227\260\354\261\204/ex5.js" "b/\354\240\225\354\227\260\354\261\204/ex5.js" index 464a05a..e43af8d 100644 --- "a/\354\240\225\354\227\260\354\261\204/ex5.js" +++ "b/\354\240\225\354\227\260\354\261\204/ex5.js" @@ -1,3 +1,42 @@ module.exports = { - searchByKoreanInitialSound: (data, firstSounds) => {}, -}; + searchByKoreanInitialSound: (data, firstSounds) => { + const HangulList = [ + "ㄱ", + "ㄲ", + "ㄴ", + "ㄷ", + "ㄸ", + "ㄹ", + "ㅁ", + "ㅂ", + "ㅃ", + "ㅅ", + "ㅆ", + "ㅇ", + "ㅈ", + "ㅉ", + "ㅊ", + "ㅋ", + "ㅌ", + "ㅍ", + "ㅎ", + ]; + + const getHangul = (ch) => { + const code = ch.charCodeAt(0) - 0xac00; + return code >= 0 && code < 11172 ? HangulList[Math.floor(code / 588)] : ch; + }; + + const regex = new RegExp( + firstSounds + .split("") + .map((char) => (/[ㄱ-ㅎ]/.test(char) ? char : `(${char})`)) + .join(".*?") + ); + + return data.filter((item) => { + const hangulStr = item.split("").map(getHangul).join(""); + return regex.test(hangulStr); + }); + }, +}; \ No newline at end of file diff --git "a/\354\240\225\354\227\260\354\261\204/ex6.test.ts" "b/\354\240\225\354\227\260\354\261\204/ex6.test.ts" index 680c5e6..41abbf6 100644 --- "a/\354\240\225\354\227\260\354\261\204/ex6.test.ts" +++ "b/\354\240\225\354\227\260\354\261\204/ex6.test.ts" @@ -8,7 +8,7 @@ import { promiseAllSettled, randTime } from './ex6'; ); })(); -(async function testWithReject() { +(async function testWithReject() { assert.deepStrictEqual( await promiseAllSettled([ randTime(11), @@ -22,3 +22,4 @@ import { promiseAllSettled, randTime } from './ex6'; ]) ); })(); + diff --git "a/\354\240\225\354\227\260\354\261\204/ex6.ts" "b/\354\240\225\354\227\260\354\261\204/ex6.ts" index 424ca54..29ad355 100644 --- "a/\354\240\225\354\227\260\354\261\204/ex6.ts" +++ "b/\354\240\225\354\227\260\354\261\204/ex6.ts" @@ -1,4 +1,48 @@ export const randTime = (val: T): Promise => - new Promise(resolve => setTimeout(resolve, Math.random() * 1000, val)); + new Promise((resolve) => setTimeout(resolve, Math.random() * 1000, val)); -export function promiseAllSettled(promises: Promise[]) {} +export function promiseAllSettled( + promises: Promise[] +): Promise[]> { + return new Promise((resolve) => { + const results: PromiseSettledResult[] = []; + let cnt = 0; + + const result = (i: number, v: PromiseSettledResult) => { + results[i] = v; + cnt++; + if (cnt === promises.length) { + resolve(results); + } + }; + + promises.forEach((promise, i) => { + promise + .then((value) => + result(i, { status: "fulfilled", value } as const) + ) + .catch((reason) => + result(i, { status: "rejected", reason } as const) + ); + }); + }); +} + +export function promiseAll(promises: Promise[]): Promise { + return new Promise((resolve, reject) => { + const results: T[] = []; + let cnt = 0; + + const result = (i: number, v: T) => { + results[i] = v; + cnt++; + if (cnt === promises.length) { + resolve(results); + } + }; + + promises.forEach((promise, i) => { + promise.then((v) => result(i, v)).catch(reject); + }); + }); +} \ No newline at end of file diff --git "a/\354\240\225\354\227\260\354\261\204/ex7.test.ts" "b/\354\240\225\354\227\260\354\261\204/ex7.test.ts" index 62b881d..72b684b 100644 --- "a/\354\240\225\354\227\260\354\261\204/ex7.test.ts" +++ "b/\354\240\225\354\227\260\354\261\204/ex7.test.ts" @@ -65,6 +65,10 @@ async function test(userId: string | number) { }); // 추가 테스트 코드를 작성하시오. + + const emptyPosts = await getPosts(999); + assert.strictEqual(emptyPosts.length, 0); } test(1); + diff --git "a/\354\240\225\354\227\260\354\261\204/ex7.ts" "b/\354\240\225\354\227\260\354\261\204/ex7.ts" index 62812ac..4e2d1d8 100644 --- "a/\354\240\225\354\227\260\354\261\204/ex7.ts" +++ "b/\354\240\225\354\227\260\354\261\204/ex7.ts" @@ -1,3 +1,53 @@ +// const POST_URL = 'https://jsonplaceholder.typicode.com/posts'; + +// export async function getPosts(userId: number | string) {} + const POST_URL = 'https://jsonplaceholder.typicode.com/posts'; -export async function getPosts(userId: number | string) {} +interface Comment { + postId: number; + id: number; + email: string; + body: string; +} + +interface Post { + postId: number; + title: string; + comments: Comment[]; +} + +export async function getPosts(userId: number | string) { + try { + // 1. 특정 userId의 게시글 목록을 가져옵니다. + const postsResponse = await fetch(`${POST_URL}?userId=${userId}`); + const postsData = (await postsResponse.json()) as { id: number; title: string }[]; + + // 2. 각 게시글의 댓글 목록을 가져와서 posts 배열에 추가합니다. + const postsWithComments: Post[] = await Promise.all( + postsData.map(async (post) => { + const commentsResponse = await fetch(`${POST_URL}/${post.id}/comments`); + const commentsData = (await commentsResponse.json()) as any[]; + + // 'name' 필드를 제거하고 새로운 Comment 객체 배열을 생성합니다. + const sanitizedCommentsData: Comment[] = commentsData.map(({ postId, id, email, body }) => ({ + postId, + id, + email, + body, + })); + + return { + postId: post.id, + title: post.title, + comments: sanitizedCommentsData, + }; + }) + ); + + return postsWithComments; + } catch (error) { + console.error('오류1', error); + throw new Error('오류2'); + } +} diff --git "a/\354\240\225\354\227\260\354\261\204/ex8.ts" "b/\354\240\225\354\227\260\354\261\204/ex8.ts" index a67a2d2..a67e90a 100644 --- "a/\354\240\225\354\227\260\354\261\204/ex8.ts" +++ "b/\354\240\225\354\227\260\354\261\204/ex8.ts" @@ -1,8 +1,40 @@ -// dummy(mock)입니다. 올바르게 수정하세요. -const debounce = (cb: any, delay: number) => (i: number) => {}; -const throttle = (cb: any, delay: number) => (i: number) => {}; +// // dummy(mock)입니다. 올바르게 수정하세요. +// const debounce = (cb: any, delay: number) => (i: number) => {}; +// const throttle = (cb: any, delay: number) => (i: number) => {}; -// function throttle... +// // function throttle... + +// const debo = debounce((a: number) => console.log(a + 1), 500); +// for (let i = 10; i < 15; i++) debo(i); // 15 출력 + +// const thro = throttle((a: number) => console.log(a + 1), 500); +// for (let i = 10; i < 15; i++) thro(i); // 11 출력 + + + +const debounce = (cb: (arg: number) => void, delay: number) => { + let time: ReturnType | null = null; + + return (i: number) => { + if (time !== null) clearTimeout(time); + + time = setTimeout(() => { + cb(i); + }, delay); + }; +}; + +const throttle = (cb: (arg: number) => void, delay: number) => { + let time = 0; + + return (i: number) => { + const now = Date.now(); + if (now - time >= delay) { + cb(i); + time = now; + } + }; +}; const debo = debounce((a: number) => console.log(a + 1), 500); for (let i = 10; i < 15; i++) debo(i); // 15 출력