Вивчай
Домашнє завдання #11 · Методи масивів: map, filter, reduce, sort, find
100 балів+10 бонусintermediate

Домашнє завдання #11: Кіноаналітика — вижми все з датасету

Уяви: тебе взяли аналітиком у стрімінговий сервіс. Перше завдання від боса — «ось дані по фільмах, до вечора хочу знати: що в нас найкраще, хто найкасовіший режисер і що порадити глядачу на вечір». Справжні дата-аналітики роблять це тими самими map/filter/reduce, які ти вивчив. Час і тобі.


Датасет

Скопіюй масив у свій script.js без змін — усі очікувані результати нижче пораховані саме для нього:

const movies = [
  { title: "Темний лицар", year: 2008, genre: "бойовик", rating: 9.0, boxOffice: 1006, director: "Крістофер Нолан" },
  { title: "Початок", year: 2010, genre: "фантастика", rating: 8.8, boxOffice: 837, director: "Крістофер Нолан" },
  { title: "Інтерстеллар", year: 2014, genre: "фантастика", rating: 8.7, boxOffice: 701, director: "Крістофер Нолан" },
  { title: "Оппенгеймер", year: 2023, genre: "драма", rating: 8.3, boxOffice: 976, director: "Крістофер Нолан" },
  { title: "Матриця", year: 1999, genre: "фантастика", rating: 8.7, boxOffice: 467, director: "Лана і Ліллі Вачовскі" },
  { title: "Форрест Ґамп", year: 1994, genre: "драма", rating: 8.8, boxOffice: 678, director: "Роберт Земекіс" },
  { title: "Паразити", year: 2019, genre: "драма", rating: 8.5, boxOffice: 263, director: "Пон Джун Хо" },
  { title: "Аватар", year: 2009, genre: "фантастика", rating: 7.9, boxOffice: 2923, director: "Джеймс Кемерон" },
  { title: "Титанік", year: 1997, genre: "драма", rating: 7.9, boxOffice: 2264, director: "Джеймс Кемерон" },
  { title: "Джокер", year: 2019, genre: "драма", rating: 8.4, boxOffice: 1074, director: "Тодд Філліпс" },
  { title: "Вовк з Волл-стріт", year: 2013, genre: "драма", rating: 8.2, boxOffice: 407, director: "Мартін Скорсезе" },
  { title: "Гладіатор", year: 2000, genre: "бойовик", rating: 8.5, boxOffice: 465, director: "Рідлі Скотт" },
  { title: "Шалений Макс: Дорога люті", year: 2015, genre: "бойовик", rating: 8.1, boxOffice: 380, director: "Джордж Міллер" },
  { title: "Король Лев", year: 1994, genre: "анімація", rating: 8.5, boxOffice: 968, director: "Роджер Аллерс і Роб Мінкофф" },
  { title: "Захар Беркут", year: 2019, genre: "бойовик", rating: 6.7, boxOffice: 1.5, director: "Ахтем Сеітаблаєв" },
  { title: "Мавка. Лісова пісня", year: 2023, genre: "анімація", rating: 6.9, boxOffice: 21, director: "Олег Маламуж і Олександра Рубан" },
  { title: "Памфір", year: 2023, genre: "драма", rating: 7.1, boxOffice: 0.2, director: "Дмитро Сухолиткий-Собчук" },
];

boxOffice — світова каса в мільйонах доларів. Так, «Аватар» справді зібрав майже 3 мільярди. І так, тут є українські фільми — аналітика без «Мавки» і «Захара Беркута» була б неповною.

Головне правило: жодного циклу for/while. Тільки методи масивів — це окремий критерій на 15 балів.


Завдання: 7 функцій

1. topRated(movies, n) — топ-n за рейтингом

Повертає масив назв n найрейтинговіших фільмів (від найвищого). Порядок фільмів з однаковим рейтингом — неважливий. Оригінальний масив не змінюється!

ВикликРезультат
topRated(movies, 5)["Темний лицар", "Початок", "Форрест Ґамп", "Інтерстеллар", "Матриця"]
topRated(movies, 3)["Темний лицар", "Початок", "Форрест Ґамп"]

2. releasedAfter(movies, year) — новинки

Масив фільмів (об'єктів), випущених строго після зазначеного року.

ВикликРезультат
releasedAfter(movies, 2018)6 фільмів: Оппенгеймер, Паразити, Джокер, Захар Беркут, Мавка. Лісова пісня, Памфір
releasedAfter(movies, 2023)[]

3. boxOfficeByGenre(movies) — каса по жанрах

Через reduce збери об'єкт { жанр: сумарна каса } (порядок ключів — неважливий):

boxOfficeByGenre(movies);
// { "бойовик": 1852.5, "фантастика": 4928, "драма": 5662.2, "анімація": 989 }

4. directorRating(movies, director) — середній рейтинг режисера

Число, округлене до 2 знаків. Якщо режисера в датасеті немає — рядок "Режисера не знайдено".

ВикликРезультат
directorRating(movies, "Крістофер Нолан")8.7
directorRating(movies, "Джеймс Кемерон")7.9
directorRating(movies, "Стівен Спілберг")"Режисера не знайдено"

5. bestYear(movies) — найприбутковіший рік

Об'єкт { year, total } — рік із найбільшою сумарною касою:

bestYear(movies);
// { year: 2009, total: 2923 }

6. searchByTitle(movies, query) — пошук

Масив фільмів, у назві яких є підрядок query. Регістр — неважливий.

ВикликРезультат
searchByTitle(movies, "ар")2 фільми: Аватар, Захар Беркут
searchByTitle(movies, "МАВ")1 фільм: Мавка. Лісова пісня
searchByTitle(movies, "хоббіт")[]

7. recommend(movies, genre, minRating) — порадник на вечір

Випадковий фільм (об'єкт) заданого жанру з рейтингом строго вище minRating. Якщо кандидатів немає — рядок "Нічого не знайдено".

ВикликРезультат
recommend(movies, "драма", 8.4)випадково: Форрест Ґамп або Паразити
recommend(movies, "анімація", 9)"Нічого не знайдено"

Бонус (+10): Pipeline «топ-3 драми 2010-х за касою»

Функція top3DramasOf2010s(movies)один ланцюжок методів (без проміжних змінних): відфільтрувати драми 2010–2019 років → відсортувати за касою (спадання) → взяти перші 3 → повернути масив назв.

top3DramasOf2010s(movies);
// ["Джокер", "Вовк з Волл-стріт", "Паразити"]

Підказки

Рівень 1: напрямок думки
  • Кожна функція — це комбінація 1–3 методів: спершу відбери потрібне (filter), потім перетвори (map) або згорни в одне значення (reduce)
  • «Найкращий рік» — це два кроки: спершу зведи касу по роках в об'єкт (як у жанрах), потім знайди ключ із максимальним значенням
  • Випадковий елемент масиву — випадковий індекс від 0 до довжини
Рівень 2: які методи використати
  • sort мутує масив — сортуй копію: [...movies].sort((a, b) => b.rating - a.rating)
  • Пошук без регістру: title.toLowerCase().includes(query.toLowerCase())
  • Округлення до 2 знаків: Math.round(avg * 100) / 100
  • Максимум серед пар ключ-значення: Object.entries(totals) дає масив пар — його теж можна прогнати через reduce
  • Перші n елементів: slice(0, n)
Рівень 3: псевдокод boxOfficeByGenre
функція boxOfficeByGenre(movies):
  повернути movies.reduce((acc, movie) => {
    якщо в acc ще немає ключа movie.genre → створити його зі значенням 0
    додати movie.boxOffice до acc[movie.genre]
    повернути acc
  }, порожній об'єкт)

Як здати

  1. Робота — в публічному GitHub-репозиторії курсу my-web-course, у папці hw-11/
  2. У папці: script.js (датасет + 7 функцій + демо-виклик кожної з console.log) та index.html-обгортка:
<!DOCTYPE html>
<html lang="uk">
<head><meta charset="UTF-8"><title>HW-11</title></head>
<body>
  <script src="script.js"></script>
</body>
</html>
  1. Відкрий index.html → консоль (F12): звіт для боса готовий
  2. У папці — README.md: 2-3 речення що зроблено + як запустити
  3. Мінімум 3 коміти з осмисленими повідомленнями (не «fix» та «update»)
  4. Надішли посилання на репозиторій у форму на цій сторінці

Критерії оцінки

КритерійТипБали
topRated — правильний топ, оригінальний масив не мутується[код]10
releasedAfter — строга нерівність, збігається з прикладами[код]10
boxOfficeByGenrereduce в об'єкт, точні суми[код]15
directorRating — середнє з округленням + випадок «не знайдено»[код]10
bestYear — об'єкт { year, total }, збігається з прикладом[код]15
searchByTitle — пошук підрядка без урахування регістру[код]10
recommend — фільтр за жанром і рейтингом + випадковий вибір + «не знайдено»[код]10
Жодного for/while — тільки методи масивів[код]15
Контракт здачі: 3+ осмислені коміти, README, демо-виклики[код]5
Бонус: pipeline top3DramasOf2010s одним ланцюжком[код]+10

Що далі

Цей стиль — фільтри, сортування, трансформації даних — рівно те, чим ти займатимешся в React (Block 8): там список фільмів рендериться через той самий map. А в ДЗ #16 ти завантажиш такі дані вже не з константи, а з реального API.