# Домашнє завдання · Тема 06 · Списки

> Лекція: [lecture.html](lecture.html) · Практика: [practice.ipynb](practice.ipynb) · Тест: [quiz.html](quiz.html)

Циклів (`for`) у курсі ще не було — вони будуть у темі 12. Усі три рівні
розвʼязуються без жодної ітерації: індексами, зрізами, методами списку
й вбудованими функціями. Скрізь перевіряй себе через `assert`: спершу запиши,
який результат очікуєш, і тільки потім запускай.

---

## 🟢 Рівень 1 — База

Збери власний список покупок і проведи його через повний життєвий цикл.

1. Створи список із **пʼяти** назв продуктів (своїх, не з лекції).
2. Додай шосту назву в кінець через `append`.
3. Встав ще одну так, щоб вона стала елементом з номером 2.
4. Прибери один продукт **за значенням** — але спершу перевір через `in`,
   що він там є.
5. Зніми останній елемент через `pop()` і збережи його в окреме імʼя.
6. Після кожної дії друкуй список і його довжину.

**Зроблено, якщо:** у фінальному списку рівно 5 елементів, у коді є
`assert len(мій_список) == 5` і `assert знятий_елемент == "…"` з тим значенням,
яке ти очікував побачити ще до запуску.

---

## 🟡 Рівень 2 — Плюс

Візьми список із восьми назв **різної довжини** (щоб були групи однакової довжини —
це знадобиться в останньому пункті).

1. Отримай три результати, **не зіпсувавши оригінал**: відсортований за абеткою,
   відсортований за довжиною назви (`key=len`) і перевернутий.
2. Тепер зроби те саме через методи, які псують оригінал (`sort`, `reverse`) —
   але спершу відклади копію, щоб було з чим порівняти.
3. У коментарі поясни одним реченням, у якому випадку доречніший метод,
   а в якому — функція.
4. Знайди у відсортованому за довжиною списку групу з однаковою довжиною назви
   й доведи `assert`-ом, що всередині цієї групи порядок такий самий,
   як був у вихідному списку.

**Зроблено, якщо:** після всіх операцій `assert вихідний == [ … ]` підтверджує,
що список дослівно збігається з тим, яким ти його створив, і є окремий `assert`
на стабільність із пункту 4.

---

## 🔴 Рівень 3 — Виклик

Дослідження на дві частини.

### Частина А — таблиця

1. Побудуй таблицю 4×4 з нулів двома способами: через `[[0] * 4] * 4`
   і через спискове включення `[[0] * 4 for _ in range(4)]`.
2. В обох постав одиницю в клітинку `[0][0]` і надрукуй результати.
3. `assert`-ами покажи, чим вони відрізняються: у зламаній таблиці
   `таблиця[0] is таблиця[1]`, у правильній — ні.

### Частина Б — копії

1. Візьми правильну таблицю й зроби з неї дві копії: поверхневу
   (`.copy()`) і глибоку (`copy.deepcopy`).
2. У **кожній** копії зміни клітинку `[1][1]` на 7.
3. `assert`-ами доведи, яка з копій захистила оригінал, а яка протекла —
   і на якому саме рівні вкладеності.
4. Одним реченням у коментарі сформулюй правило: коли достатньо `.copy()`,
   а коли потрібен `deepcopy`.

**Зроблено, якщо:** у коді щонайменше **чотири** `assert`, серед них
хоча б один на `is` (а не тільки на `==`) — саме він показує, що вкладені списки
поверхневої копії є **тими самими обʼєктами**, що й в оригіналі, і саме через
це вона протікає.

---

## Підказки

- `id(x)` і `x is y` — твої головні інструменти в цій темі. Рівність `==`
  каже про вміст, `is` — про те, чи це фізично один обʼєкт. Коли assert на `==`
  проходить, а на `is` ні (або навпаки) — ти щойно намацав суть.
- Якщо не певен, чи метод псує оригінал, перевір це на маленькому списку
  з двох елементів: надрукуй список **до** виклику, після виклику й окремо те,
  що виклик повернув. Три рядки — і жодних сумнівів.
- У рівні 3 частина Б стає очевидною, якщо перед `assert`-ами надрукувати
  `копія[1] is оригінал[1]` для обох копій. Один рядок дасть `True`,
  другий `False` — далі лишиться тільки пояснити чому.
