diff --git a/index.js b/index.js index 4d633a5..a64b0e9 100644 --- a/index.js +++ b/index.js @@ -19,7 +19,9 @@ const books = [ * getTitlesByCategory(books, "소설") // → ["어린왕자", "1984", "해리포터"] */ function getTitlesByCategory(books, category) { - // 여기를 작성하세요 + return books + .filter((book) => book.category === category) + .map((book) => book.title); } /** @@ -31,7 +33,9 @@ function getTitlesByCategory(books, category) { * getTotalPriceAbove(books, 15000) // → 85000 */ function getTotalPriceAbove(books, threshold) { - // 여기를 작성하세요 + return books + .filter((book) => book.price >= threshold) + .reduce((sum, book) => sum + book.price, 0); } /** @@ -42,7 +46,7 @@ function getTotalPriceAbove(books, threshold) { * isAllSameCategory([{ category: "소설" }, { category: "소설" }], "소설") // → true */ function isAllSameCategory(books, category) { - // 여기를 작성하세요 + return books.every((book) => book.category === category); } // ───────────────────────────────────────────── @@ -58,7 +62,9 @@ function isAllSameCategory(books, category) { * formatBookLabel({ title: "어린왕자", author: "생텍쥐페리" }) // → "어린왕자 - 생텍쥐페리" */ function formatBookLabel(book) { - // 여기를 작성하세요 + const { title, author } = book; + + return `${title} - ${author}`; } /** @@ -69,7 +75,9 @@ function formatBookLabel(book) { * const { first, rest } = splitFirstAndRest(books) */ function splitFirstAndRest(books) { - // 여기를 작성하세요 + const [first, ...rest] = books; + + return { first, rest }; } /** @@ -81,7 +89,9 @@ function splitFirstAndRest(books) { * omitPrice({ title: "어린왕자", price: 12000 }) // → { title: "어린왕자" } */ function omitPrice(book) { - // 여기를 작성하세요 + const { price, ...rest } = book; + + return rest; } // ───────────────────────────────────────────── @@ -96,7 +106,17 @@ function omitPrice(book) { * // → Map { "소설" => ["어린왕자", "1984", "해리포터"], "교육" => [...] } */ function groupByCategory(books) { - // 여기를 작성하세요 + return books.reduce((map, book) => { + const { category, title } = book; + + if (!map.has(category)) { + map.set(category, []); + } + + map.get(category).push(title); + + return map; + }, new Map()); } /** @@ -108,7 +128,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 +141,7 @@ function intersection(arrA, arrB) { * unique([1, 2, 2, 3]) // → [1, 2, 3] */ function unique(arr) { - // 여기를 작성하세요 + return [...new Set(arr)]; } // ───────────────────────────────────────────── @@ -134,7 +156,9 @@ function unique(arr) { * getOutOfStock({ 어린왕자: 3, "1984": 0 }) // → ["1984"] */ function getOutOfStock(stock) { - // 여기를 작성하세요 + return Object.entries(stock) + .filter(([_, quantity]) => quantity === 0) + .map(([title]) => title); } /** @@ -145,7 +169,10 @@ function getOutOfStock(stock) { * getTotalStock({ 어린왕자: 3, "1984": 0, 해리포터: 2 }) // → 5 */ function getTotalStock(stock) { - // 여기를 작성하세요 + return Object.values(stock).reduce( + (sum, quantity) => sum + quantity, + 0 + ); } /** @@ -156,7 +183,11 @@ function getTotalStock(stock) { * removeNullish({ title: "어린왕자", author: null }) // → { title: "어린왕자" } */ function removeNullish(obj) { - // 여기를 작성하세요 + return Object.fromEntries( + Object.entries(obj).filter( + ([_, value]) => value !== null && value !== undefined + ) + ); } // ───────────────────────────────────────────── @@ -174,7 +205,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 +239,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 +258,12 @@ function sortBy(books, key) { * // → [{ title: "어린왕자", price: 12000, category: "소설" }] */ function flattenCategories(categories) { - // 여기를 작성하세요 + return categories.flatMap(({ category, books }) => + books.map((book) => ({ + ...book, + category, + })) + ); } // ───────────────────────────────────────────── @@ -223,7 +284,11 @@ function flattenCategories(categories) { * for (const book of createBookIterator(books)) { ... } */ function createBookIterator(books) { - // 여기를 작성하세요 + function* iterator() { + yield* books; + } + + return iterator(); } /** @@ -236,7 +301,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": [