diff --git a/index.js b/index.js index 4d633a5..97932b2 100644 --- a/index.js +++ b/index.js @@ -1,9 +1,39 @@ const books = [ - { title: "어린왕자", author: "생텍쥐페리", year: 1943, category: "소설", price: 12000 }, - { title: "1984", author: "조지 오웰", year: 1949, category: "소설", price: 15000 }, - { title: "수학의 정석", author: "홍성대", year: 1966, category: "교육", price: 20000 }, - { title: "코딩 테스트", author: "나동빈", year: 2021, category: "교육", price: 32000 }, - { title: "해리포터", author: "J.K. 롤링", year: 1997, category: "소설", price: 18000 }, + { + title: '어린왕자', + author: '생텍쥐페리', + year: 1943, + category: '소설', + price: 12000, + }, + { + title: '1984', + author: '조지 오웰', + year: 1949, + category: '소설', + price: 15000, + }, + { + title: '수학의 정석', + author: '홍성대', + year: 1966, + category: '교육', + price: 20000, + }, + { + title: '코딩 테스트', + author: '나동빈', + year: 2021, + category: '교육', + price: 32000, + }, + { + title: '해리포터', + author: 'J.K. 롤링', + year: 1997, + category: '소설', + price: 18000, + }, ]; // ───────────────────────────────────────────── @@ -19,7 +49,9 @@ const books = [ * getTitlesByCategory(books, "소설") // → ["어린왕자", "1984", "해리포터"] */ function getTitlesByCategory(books, category) { - // 여기를 작성하세요 + return books + .filter((book) => book.category === category) + .map((book) => book.title); } /** @@ -31,7 +63,9 @@ function getTitlesByCategory(books, category) { * getTotalPriceAbove(books, 15000) // → 85000 */ function getTotalPriceAbove(books, threshold) { - // 여기를 작성하세요 + return books + .filter((book) => book.price >= threshold) + .reduce((acc, book) => acc + book.price, 0); } /** @@ -42,7 +76,7 @@ function getTotalPriceAbove(books, threshold) { * isAllSameCategory([{ category: "소설" }, { category: "소설" }], "소설") // → true */ function isAllSameCategory(books, category) { - // 여기를 작성하세요 + return books.every((book) => book.category === category); } // ───────────────────────────────────────────── @@ -58,7 +92,9 @@ function isAllSameCategory(books, category) { * formatBookLabel({ title: "어린왕자", author: "생텍쥐페리" }) // → "어린왕자 - 생텍쥐페리" */ function formatBookLabel(book) { - // 여기를 작성하세요 + const { title, author } = book; + + return `${title} - ${author}`; } /** @@ -69,7 +105,9 @@ function formatBookLabel(book) { * const { first, rest } = splitFirstAndRest(books) */ function splitFirstAndRest(books) { - // 여기를 작성하세요 + const [first, ...rest] = books; + + return { first, rest }; } /** @@ -81,7 +119,8 @@ function splitFirstAndRest(books) { * omitPrice({ title: "어린왕자", price: 12000 }) // → { title: "어린왕자" } */ function omitPrice(book) { - // 여기를 작성하세요 + const { price, ...rest } = book; + return rest; } // ───────────────────────────────────────────── @@ -96,7 +135,17 @@ function omitPrice(book) { * // → Map { "소설" => ["어린왕자", "1984", "해리포터"], "교육" => [...] } */ function groupByCategory(books) { - // 여기를 작성하세요 + const result = new Map(); + + for (const book of books) { + if (!result.has(book.category)) { + result.set(book.category, []); + } + + result.get(book.category).push(book.title); + } + + return result; } /** @@ -108,7 +157,9 @@ function groupByCategory(books) { * intersection([1, 2, 3], [2, 3, 4]) // → [2, 3] */ function intersection(arrA, arrB) { - // 여기를 작성하세요 + const setB = new Set(arrB); + + return [...new Set(arrA.filter((item) => setB.has(item)))]; } /** @@ -119,7 +170,7 @@ function intersection(arrA, arrB) { * unique([1, 2, 2, 3]) // → [1, 2, 3] */ function unique(arr) { - // 여기를 작성하세요 + return [...new Set(arr)]; } // ───────────────────────────────────────────── @@ -134,7 +185,9 @@ function unique(arr) { * getOutOfStock({ 어린왕자: 3, "1984": 0 }) // → ["1984"] */ function getOutOfStock(stock) { - // 여기를 작성하세요 + return Object.entries(stock) + .filter(([title, quantity]) => quantity === 0) + .map(([title, quantity]) => title); } /** @@ -145,7 +198,7 @@ function getOutOfStock(stock) { * getTotalStock({ 어린왕자: 3, "1984": 0, 해리포터: 2 }) // → 5 */ function getTotalStock(stock) { - // 여기를 작성하세요 + return Object.values(stock).reduce((sum, quantity) => sum + quantity, 0); } /** @@ -156,7 +209,11 @@ function getTotalStock(stock) { * removeNullish({ title: "어린왕자", author: null }) // → { title: "어린왕자" } */ function removeNullish(obj) { - // 여기를 작성하세요 + return Object.fromEntries( + Object.entries(obj).filter( + ([key, value]) => value !== null && value !== undefined, + ), + ); } // ───────────────────────────────────────────── @@ -174,7 +231,28 @@ function removeNullish(obj) { * getAvgPriceByCategory(books) // → { 소설: 15000, 교육: 26000 } */ function getAvgPriceByCategory(books) { - // 여기를 작성하세요 + const grouped = books.reduce((acc, book) => { + const { category, price } = book; + + if (!acc[category]) { + acc[category] = { + sum: 0, + count: 0, + }; + } + + acc[category].sum += price; + acc[category].count += 1; + + return acc; + }, {}); + + return Object.fromEntries( + Object.entries(grouped).map(([category, info]) => [ + category, + info.sum / info.count, + ]), + ); } /** @@ -187,7 +265,11 @@ function getAvgPriceByCategory(books) { * sortBy(books, "title") // → 제목 가나다순 새 배열 */ function sortBy(books, key) { - // 여기를 작성하세요 + return [...books].sort((a, b) => { + if (a[key] > b[key]) return 1; + if (a[key] < b[key]) return -1; + return 0; + }); } /** @@ -202,7 +284,12 @@ function sortBy(books, key) { * // → [{ title: "어린왕자", price: 12000, category: "소설" }] */ function flattenCategories(categories) { - // 여기를 작성하세요 + return categories.flatMap((categoryGroup) => + categoryGroup.books.map((book) => ({ + ...book, + category: categoryGroup.category, + })), + ); } // ───────────────────────────────────────────── @@ -222,8 +309,10 @@ function flattenCategories(categories) { * * for (const book of createBookIterator(books)) { ... } */ -function createBookIterator(books) { - // 여기를 작성하세요 +function* createBookIterator(books) { + for (const book of books) { + yield book; + } } /** @@ -236,7 +325,20 @@ function createBookIterator(books) { * paginate(books, 1, 2) // → { data: [books[0], books[1]], totalPages: 3, currentPage: 1 } */ function paginate(books, page, size) { - // 여기를 작성하세요 + const totalPages = Math.ceil(books.length / size); + + if (page < 1 || page > totalPages) { + throw new Error('유효하지 않은 페이지 번호입니다.'); + } + + const start = (page - 1) * size; + const end = start + size; + + return { + data: books.slice(start, end), + totalPages, + currentPage: page, + }; } // ───────────────────────────────────────────── diff --git a/package-lock.json b/package-lock.json index e6e7363..4afc3b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1278,9 +1278,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1295,9 +1292,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1312,9 +1306,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1329,9 +1320,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1346,9 +1334,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1363,9 +1348,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1380,9 +1362,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1397,9 +1376,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1414,9 +1390,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1431,9 +1404,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [