OOP Course
Сьогодні

Lab 02

Масиви

Пошук, сортування, 2D-розклад

Лаба 02 — Масиви

Мета

Навчитися працювати з одновимірними, двовимірними, рваними та тривимірними масивами в C#.

Контекст

Друга — і остання — лаба-тренажер. Тут ви відпрацьовуєте масиви всіх видів: одновимірні, прямокутні 2D, рвані (jagged) та тривимірні. Це фундамент: у Лабі 03 менеджери колекцій (PatientManager тощо) зберігатимуть об'єкти саме в масивах із ручним лічильником, поки в Лабі 09 не з'явиться List<T>.

Як і Лаба 01, це окремий проєкт Lab02/, який не стає частиною системи.

Нагадування про робочий процес (деталі — Git Воркшоп): кожна лаба = гілка Lab-XX від main. З Лаби 03 гілка зливається назад у main. Лаби 01 і 02 — виняток: гілку пушите на GitHub, але в main НЕ зливаєте. Коміт на кожне завдання, формат — LabXX TaskYY (напр. Lab02 Task03).

Структура проєкту на початку лаби

Це стан гілки main перед початком роботи. Проєкт Lab01/ лишився на гілці Lab-01 і в main не потрапив, тому тут його немає:

oop-course/                          ← гілка main
├── .gitignore
└── oop-course.slnx

Вигляд проєкту наприкінці лаби — у розділі «Структура проєкту наприкінці лаби» перед перевіркою.


Крок 1. Проєкт для Лаби 02

Рішення oop-course.slnx і .gitignore вже створені в Лабі 01 (Крок 0). Тут — лише нова гілка й новий проєкт.

git checkout main
git checkout -b Lab-02

dotnet new console -o Lab02 --name Lab02
dotnet sln add Lab02/Lab02.csproj
dotnet run --project Lab02          # має вивести Hello, World!

git add oop-course.slnx Lab02/
git commit -m "Lab02: project"

Як виконувати завдання

Кожне завдання — окремий файл TaskN.cs у теці Lab02/ (клас TaskN з методом Run()). У Lab02/Program.cs — один рядок-виклик, який ви міняєте після кожного завдання:

// Дробові числа вводимо з КРАПКОЮ незалежно від локалі Windows.
System.Threading.Thread.CurrentThread.CurrentCulture =
    System.Globalization.CultureInfo.InvariantCulture;

Task1.Run();   // → Task2.Run() → Task3.Run() → ...

Після кожного завдання — коміт Lab02 TaskNN.

Як і в Лабі 01: Console.ReadLine() пишемо зі знаком ! перед Parse — int.Parse(Console.ReadLine()!). Це прибирає попередження nullable-аналізу. Тему nullable-типів розберемо в Лабі 03.

Ваш домен

За замовчуванням виконуйте завдання як написано. Якщо ведете власний домен — таблиця «Адаптація до вашого домену» в кінці кожного завдання показує, чим замінити суть; формат вводу/виводу й структуру коду зберігайте.

Як користуватися підказками

Підказки — це напрям думки, а не готовий код. Кожна закінчується блоком 📖 Документація. Спершу читаєте документацію і пробуєте самі, і лише якщо застрягли — берете наступний крок підказки.


Задача 1. Ваги пацієнтів ⭐

Умова

Зчитайте N ваг пацієнтів у масив і обрахуйте статистику: середнє, мінімум, максимум і кількість пацієнтів з вагою вище середньої.

Формат вводу

Рядок Поле Тип
1 N — кількість пацієнтів int (> 0)
2 … N+1 вага пацієнта double (кг)

Приклади

Приклад 1:

N ваги Вихід
5 70.0, 85.5, 62.0, 91.0, 78.3 Кількість: 5 / Середня вага: 77.4 кг / Мін / Макс: 62.0 / 91.0 кг / Вище середнього: 3 з 5

Приклад 2:

N ваги Вихід
3 55.0, 70.0, 90.0 Кількість: 3 / Середня вага: 71.7 кг / Мін / Макс: 55.0 / 90.0 кг / Вище середнього: 1 з 3

Підказки

  1. Спершу N, потім масив. Прочитайте кількість пацієнтів, оголосіть одновимірний масив рівно на N елементів. Синтаксис створення масиву — у документації.
  2. Заповнення. Пройдіться for від 0 до N-1, у кожній ітерації читаючи одне число з консолі в комірку масиву.
  3. Перший прохід — агрегати. Один foreach по масиву, у якому ви водночас накопичуєте суму та відстежуєте поточні мінімум і максимум. Початкові значення для min/max беріть з першого елемента, не з нуля.
  4. Середнє — сума поділена на кількість. Слідкуйте за типом ділення.
  5. Другий прохід — порівняння із середнім. Середнє відоме лише після кроку 3, тому «скільки ваг вище середнього» рахується окремим циклом.
  6. Формат виводу — дивіться приклади: одне число після коми (F1).

📖 Документація:

Адаптація до вашого домену

Домен Масив Статистика
Готель ціни номерів (double) середня ціна, найдешевший, найдорожчий
Ресторан ваги порцій (double) середня вага, мін/макс, скільки понад норму
Університет бали студентів (int) середній бал, мін/макс, скільки ≥ 90
Прокат авто пробіги (double, тис. км) середній пробіг, мін/макс, скільки потребують ТО (> 150)

Коміт

git add Lab02/Task1.cs Lab02/Program.cs
git commit -m "Lab02 Task01"

Задача 2. Сортування черги прийомів ⭐

Умова

Зчитайте N вартостей прийомів у масив, відсортуйте методом бульбашки (bubble sort) за зростанням і виведіть результат.

Формат вводу

Рядок Поле Тип
1 N — кількість int (> 0)
2 … N+1 вартість прийому int (грн)

Приклади

N вартості (до) Вихід (після) мін макс
5 500 200 800 350 150 150 200 350 500 800 150 800
3 300 100 200 100 200 300 100 300
4 1000 500 750 250 250 500 750 1000 250 1000

Вихід для першого прикладу:

Черга (до):    500 200 800 350 150
Черга (після): 150 200 350 500 800
Найдешевший:   150 грн
Найдорожчий:   800 грн

Підказки

  1. Зафіксуйте «до». Одразу після зчитування збережіть рядок із початковою чергою в окрему змінну — інакше після сортування ви його вже не покажете.
  2. Bubble sort — два вкладені цикли. Зовнішній повторює прохід по масиву, внутрішній порівнює сусідні пари queue[j] і queue[j+1]. З кожним зовнішнім проходом найбільше число «спливає» в кінець, тому діапазон внутрішнього циклу можна щоразу скорочувати. Розберіть алгоритм по кроках у документації (посилання нижче).
  3. Обмін двох комірок. Класичний спосіб — через тимчасову змінну. C# також уміє обмін одним рядком через кортеж — знайдіть «tuple / deconstruction».
  4. Після сортування за зростанням мінімум — у queue[0], максимум — в останній комірці.
  5. Вивід масиву в рядок — метод, який склеює елементи через роздільник (шукайте string.Join).

📖 Документація:

Адаптація до вашого домену

Домен Що сортувати Вихід
Готель ціни номерів (зростання) відсортовані ціни, мін/макс
Ресторан ваги порцій (зростання) відсортовані ваги
Університет бали студентів (спадання) рейтинг балів
Прокат авто рік випуску авто (зростання) від найстаршого до найновішого

Коміт

git add Lab02/Task2.cs Lab02/Program.cs
git commit -m "Lab02 Task02"

Задача 3. Тижневий графік клініки ⭐⭐

Умова

Зчитайте кількість пацієнтів за кожен день тижня (7 значень, Пн–Нд). Виведіть таблицю, загальну кількість, найзавантаженіший і найтихіший день.

Формат вводу

Рядок Поле Тип
1 Пн — пацієнтів int
2 Вт — пацієнтів int
3 Ср — пацієнтів int
4 Чт — пацієнтів int
5 Пт — пацієнтів int
6 Сб — пацієнтів int
7 Нд — пацієнтів int

Приклади

Приклад 1:

Пн Вт Ср Чт Пт Сб Нд
12 8 15 10 9 5 2
Понеділок   : 12 пацієнтів
Вівторок    : 8 пацієнтів
Середа      : 15 пацієнтів
Четвер      : 10 пацієнтів
П'ятниця    : 9 пацієнтів
Субота      : 5 пацієнтів
Неділя      : 2 пацієнтів
Разом:        61
Найбільше:    Середа (15)
Найменше:     Неділя (2)

Приклад 2:

Пн Вт Ср Чт Пт Сб Нд
5 5 5 5 5 0 0
...
Разом:        25
Найбільше:    Понеділок (5)
Найменше:     Субота (0)

Підказки

  1. Два паралельні масиви. Один — з назвами днів (заповнюєте його одразу літералами при оголошенні), другий — з кількістю пацієнтів (7 чисел з консолі). Індекс i в обох означає той самий день.
  2. Читання 7 значень — простий for від 0 до 6.
  3. Шукайте індекси, а не значення. Щоб вивести «Середа (15)», потрібно знати позицію максимуму: тоді назва — це days[maxIdx], а число — counts[maxIdx]. Те саме для мінімуму.
  4. Ініціалізація пошуку. maxIdx і minIdx почніть з 0 і порівнюйте решту елементів з поточним «чемпіоном».
  5. Вирівнювання стовпців у виводі задається компонентом вирівнювання в інтерполяції рядка (від'ємне число — вирівняти ліворуч). Знайдіть «composite formatting alignment» в документації.

📖 Документація:

Адаптація до вашого домену

Домен Що per день Назви
Готель кількість заїздів Пн-Нд або місяці
Ресторан кількість замовлень час доби (8 годин)
Університет відвідуваність пар Пн-Сб
Прокат авто кількість оренд Пн-Нд

Коміт

git add Lab02/Task3.cs Lab02/Program.cs
git commit -m "Lab02 Task03"

Задача 4. Матриця прийомів лікарів ⭐⭐

Умова

Зчитайте матрицю N×M, де рядок = лікар, стовпець = робочий день. Значення — кількість прийомів. Виведіть: сума прийомів по кожному лікарю (рядки), сума по кожному дню (стовпці), максимальне значення та його позицію.

Формат вводу

Рядок Поле Тип
1 N — лікарів int
2 M — днів int
3 … N+2 M чисел через пробіл (рядок матриці) int

Приклади

Приклад 1 (3×3):

Вхід:

3
3
5 3 4
2 8 1
6 2 7
Лікар 1: 12 прийомів
Лікар 2: 11 прийомів
Лікар 3: 15 прийомів
По днях: 13, 13, 12
Максимум: 8 (Лікар 2, День 2)

Приклад 2 (2×4):

Вхід:

2
4
4 3 5 2
2 5 4 7
Лікар 1: 14 прийомів
Лікар 2: 18 прийомів
По днях: 6, 8, 9, 9
Максимум: 7 (Лікар 2, День 4)

Підказки

  1. Прямокутний 2D масив оголошується з двома розмірностями через кому в дужках. Рядок = лікар, стовпець = день. Синтаксис — у документації («multidimensional arrays»).
  2. Читання рядка матриці. Ціла стрічка чисел через пробіл ділиться на частини методом, який розбиває рядок за роздільником; кожну частину перетворюєте на int.
  3. Суми по рядках. Зовнішній цикл — по лікарях (i), внутрішній — по днях (j); накопичуєте суму елементів matrix[i, j] для фіксованого i.
  4. Суми по стовпцях — навпаки. Зовнішній цикл по днях (j), внутрішній по лікарях (i). Порядок вкладення циклів визначає, що ви підсумовуєте.
  5. Максимум із позицією. Окрім самого значення зберігайте maxRow і maxCol — щоб вивести «(Лікар 2, День 2)».

📖 Документація:

Адаптація до вашого домену

Домен Рядки Стовпці Значення
Готель номери кімнат місяці кількість бронювань
Ресторан офіціанти дні тижня кількість замовлень
Університет викладачі пари на тиждень кількість студентів
Прокат авто автомобілі тижні кількість оренд

Коміт

git add Lab02/Task4.cs Lab02/Program.cs
git commit -m "Lab02 Task04"

Задача 5. Аналіз квадратної матриці ⭐⭐

Умова

Зчитайте квадратну матрицю N×N. Знайдіть елементи та суми головної і побічної діагоналей.

Головна діагональ: клітинки де i == j (зліва-зверху → праворуч-знизу)
Побічна діагональ: клітинки де i + j == N - 1 (зверху-праворуч → ліворуч-знизу)

Формат вводу

Рядок Поле Тип
1 N — розмір int (≥ 2)
2 … N+1 N чисел через пробіл int

Приклади

Приклад 1 (N=3):

Вхід:

3
1 2 3
4 5 6
7 8 9
Головна діагональ: 1, 5, 9 (сума = 15)
Побічна діагональ: 3, 5, 7 (сума = 15)

Приклад 2 (N=4):

Вхід:

4
2 4 1 3
5 8 6 7
9 1 4 2
3 6 8 5
Головна діагональ: 2, 8, 4, 5 (сума = 19)
Побічна діагональ: 3, 6, 1, 3 (сума = 13)

Підказки

  1. Обидві діагоналі проходяться одним циклом i від 0 до N−1:
    • головна — комірка, де номер рядка дорівнює номеру стовпця;
    • побічна — комірка, де номер стовпця дзеркальний: N-1-i. Виведіть на папері для N=3, щоб переконатися в формулі N-1-i.
  2. Збирайте елементи в два невеликі масиви (по N елементів кожен) — щоб потім вивести їх через кому методом склеювання рядка.
  3. Суми накопичуйте в тому ж циклі, паралельно зі збором елементів.
  4. Для N непарного центральний елемент належить обом діагоналям — це нормально, так і має бути в сумах.

📖 Документація:

Адаптація до вашого домену

Домен Матриця Що шукати на діагоналі
Готель кімнати × тижні завантаження «особливих» номерів
Ресторан страви × дні тижня продажі у стабільні «діагональні» дні
Університет студенти × предмети «перехресні» оцінки
Прокат авто авто × тижні пробіг при самозбігу авто-тижень

Коміт

git add Lab02/Task5.cs Lab02/Program.cs
git commit -m "Lab02 Task05"

Задача 6. Рваний масив — прийоми лікарів ⭐⭐⭐

Умова

Кожен лікар має різну кількість прийомів. Зчитайте рваний масив (jagged array), виведіть статистику по кожному лікарю і знайдіть лікаря з найбільшим доходом.

Формат вводу

Рядок Поле Тип
1 N — кількість лікарів int
Для кожного лікаря:
наступний K — кількість прийомів int
K рядків вартість прийому int (грн)

Приклади

Приклад 1:

Вхід:

3
4
500
300
800
200
2
1000
600
3
400
250
700
Лікар 1: 4 прийоми, сума=1800 грн, середня=450.00 грн
Лікар 2: 2 прийоми, сума=1600 грн, середня=800.00 грн
Лікар 3: 3 прийоми, сума=1350 грн, середня=450.00 грн
Найбільший дохід: Лікар 1 (1800 грн)

Приклад 2:

Вхід:

2
2
200
400
3
300
500
400
Лікар 1: 2 прийоми, сума=600 грн, середня=300.00 грн
Лікар 2: 3 прийоми, сума=1200 грн, середня=400.00 грн
Найбільший дохід: Лікар 2 (1200 грн)

Підказки

  1. Рваний масив (jagged) — це масив масивів. Зовнішній масив на N елементів ви створюєте одразу, а кожен внутрішній — окремо, коли вже знаєте його довжину K. Синтаксис int[][] — у документації («jagged arrays»).
  2. Для кожного лікаря: прочитали K → створили внутрішній масив на K комірок → прочитали K значень у нього.
  3. Різна довжина рядків — це вся суть завдання. costs[i].Length у різних i буде різним, і це правильно.
  4. Середнє по лікарю. Сума цілих поділена на кількість дасть ціле — а потрібне дробове. Одному з операндів треба явно задати тип double (приведенням). Зверніться до розділу про перетворення типів.
  5. int[][] ≠ int[,]. Перше — масив масивів (рядки різної довжини), друге — суцільна прямокутна матриця. Це різні типи з різним синтаксисом доступу.

📖 Документація:

Адаптація до вашого домену

Домен Зовнішній масив Внутрішній масив
Готель кімнати бронювання (різна к-сть за місяць)
Ресторан офіціанти чеки за зміну (різна к-сть)
Університет студенти здані предмети (різна к-сть)
Прокат авто автомобілі оренди (різна к-сть)

Коміт

git add Lab02/Task6.cs Lab02/Program.cs
git commit -m "Lab02 Task06"

Задача 7. Паралельні масиви — рейтинг ІМТ ⭐⭐⭐

Умова

Зчитайте N пацієнтів (ім'я і ІМТ) у два паралельні масиви. Відсортуйте за спаданням ІМТ методом бульбашки, переміщуючи обидва масиви синхронно. Виведіть пронумерований рейтинг.

Формат вводу

Рядок Поле Тип
1 N — кількість пацієнтів int
Для кожного:
непарний ім'я string
парний ІМТ double

Приклади

Приклад 1:

N Пацієнти (ім'я / ІМТ) Вихід
4 Ivan/28.5, Olha/22.3, Petro/35.1, Maria/19.8 #1 Petro: 35.10 / #2 Ivan: 28.50 / #3 Olha: 22.30 / #4 Maria: 19.80

Приклад 2:

N Пацієнти Вихід
3 Anna/24.0, Bob/30.5, Carl/17.2 #1 Bob: 30.50 / #2 Anna: 24.00 / #3 Carl: 17.20

Вихід для прикладу 1:

=== Рейтинг ІМТ ===
#1 Petro: 35.10
#2 Ivan: 28.50
#3 Olha: 22.30
#4 Maria: 19.80

Підказки

  1. Два паралельні масиви однакової довжини: імена (string) та значення ІМТ (double). Комірка i в обох — це один пацієнт.
  2. Сортуємо ті самі bubble-sort-проходи, що в Задачі 2, але з однією відмінністю: коли міняєте місцями два ІМТ, ви тим самим рухом міняєте місцями два імені з тими самими індексами.
  3. За спаданням. Щоб більше значення опинилось спереду, умова обміну — «поточний менший за наступний» (дзеркально до сортування за зростанням).
  4. Найтиповіша помилка — переставити тільки bmis, забувши names. Тоді рейтинг покаже правильні числа з чужими іменами. Обидва масиви рухаються синхронно.

📖 Документація:

Адаптація до вашого домену

Домен Масив 1 Масив 2 Сортування
Готель назви кімнат ціна/ніч за спаданням ціни
Ресторан назви страв калорійність за зростанням калорій
Університет імена студентів середній бал за спаданням балу
Прокат авто марка+модель рік випуску за спаданням року

Коміт

git add Lab02/Task7.cs Lab02/Program.cs
git commit -m "Lab02 Task07"

Задача 8. Тривимірний масив — аналіз відділень ⭐⭐⭐

Умова

Зчитайте тривимірний масив [відділення][тиждень][зміна], де зміна 0 = ранкова, 1 = вечірня. Виведіть аналітику по кожному відділенню і знайдіть найзавантаженіше.

Формат вводу

Рядок Поле Тип
1 D — кількість відділень int
2 W — кількість тижнів int
D×W×2 рядків пацієнтів (зміна) int

Порядок введення: [відд0, тижд0, ранок], [відд0, тижд0, вечір], [відд0, тижд1, ранок], ..., [відд1, тижд0, ранок], ...

Приклади

Приклад 1 (D=2, W=2):

Вхід:

2
2
15
10
12
8
20
15
18
12
Відділення 1:
  Тиждень 1: ранок 15, вечір 10 → разом 25
  Тиждень 2: ранок 12, вечір 8 → разом 20
  Разом: 45 пацієнтів
Відділення 2:
  Тиждень 1: ранок 20, вечір 15 → разом 35
  Тиждень 2: ранок 18, вечір 12 → разом 30
  Разом: 65 пацієнтів
Найзавантаженіше: Відділення 2 (65 пацієнтів)

Приклад 2 (D=3, W=1):

Вхід:

3
1
10
8
15
12
5
3
Відділення 1:
  Тиждень 1: ранок 10, вечір 8 → разом 18
  Разом: 18 пацієнтів
Відділення 2:
  Тиждень 1: ранок 15, вечір 12 → разом 27
  Разом: 27 пацієнтів
Відділення 3:
  Тиждень 1: ранок 5, вечір 3 → разом 8
  Разом: 8 пацієнтів
Найзавантаженіше: Відділення 2 (27 пацієнтів)

Підказки

  1. Тривимірний прямокутний масив оголошується з трьома розмірностями через коми. Виміри: [відділення, тиждень, зміна], де зміна — це 0 або 1.
  2. Три вкладені цикли: зовнішній по відділеннях, середній по тижнях, внутрішній по змінах (0..1). Порядок читання вводу — саме такий (див. «Формат вводу»).
  3. Доступ до комірки — три індекси через кому в дужках.
  4. Підсумки по відділеннях зручно накопичувати в окремому одновимірному масиві на D елементів, паралельно з основними циклами.
  5. Найзавантаженіше відділення — знову шукайте індекс максимуму в масиві підсумків, а не саме значення.

📖 Документація:

Адаптація до вашого домену

Домен Вимір 1 Вимір 2 Вимір 3
Готель поверхи місяці тип номера (стандарт/люкс)
Ресторан зали дні тижня час (обід/вечеря)
Університет факультети тижні пари (перша/друга половина дня)
Прокат авто класи авто місяці тип оренди (короткострокова/довгострокова)

Коміт

git add Lab02/Task8.cs Lab02/Program.cs
git commit -m "Lab02 Task08"

Структура проєкту наприкінці лаби

Так має виглядати ваш репозиторій, коли всі 8 завдань виконано:

oop-course/                          ← гілка Lab-02 (у main НЕ зливається)
├── .gitignore
├── oop-course.slnx                     ✏ Крок 1
└── Lab02/
    ├── Lab02.csproj                    🆕 Крок 1
    ├── Program.cs                      🆕 Крок 1   ✏ Т1 Т2 Т3 Т4 Т5 Т6 Т7 Т8
    ├── Task1.cs                        🆕 Т1
    ├── Task2.cs                        🆕 Т2
    ├── Task3.cs                        🆕 Т3
    ├── Task4.cs                        🆕 Т4
    ├── Task5.cs                        🆕 Т5
    ├── Task6.cs                        🆕 Т6
    ├── Task7.cs                        🆕 Т7
    └── Task8.cs                        🆕 Т8

Легенда: 🆕 — новий файл · ✏ — змінено вміст · Тn — номер задачі, у якій ви працюєте з файлом · Крок n — підготовчий крок на початку лаби.

Зверніть увагу: Lab01/ тут немає — вона на своїй гілці Lab-01. Проєкт Lab02/ існує лише на гілці Lab-02.


Перевірка перед здачею

dotnet run --project Lab02

Переконайтесь, що:

  • Структура проєкту збігається зі схемою вище
  • Вивід кожного завдання збігається з прикладами

Пройдіться по всіх 8 завданнях, міняючи виклик у Lab02/Program.cs.


Питання для самоперевірки

Відповіді формулюйте своїми словами; за потреби — повертайтесь до документації з підказок.

  1. Чим int[,] відрізняється від int[][] на рівні пам'яті? Наведіть задачу, де підходить лише рваний масив.
  2. У Задачі 7, якщо переставляти тільки bmis, а names лишати — що саме побачить користувач у рейтингу?
  3. У Задачі 4 суми по стовпцях рахуються зі зворотним вкладенням циклів. Що зміниться в результаті, якщо залишити порядок як для сум по рядках?
  4. Скільки всього елементів у масиві int[d, w, 2]? Виведіть формулу.
  5. Чому totals[i] / costs[i].Length дає неправильне середнє, а (double)totals[i] / costs[i].Length — правильне?
  6. У bubble sort зовнішній цикл робить N−1 прохід. Чому саме N−1, а не N?
  7. Задача 3 будує таблицю через паралельні масиви (назви + числа). Чому не можна тримати назву й число в одній комірці одного масиву?

Статус гілки

Після завершення всіх 8 завдань (кожне — окремий коміт Lab02 TaskNN на гілці Lab-02) — лише push гілки, без злиття в main:

git push -u origin Lab-02

Лаба 02, як і Лаба 01, — тренажер, тому в main не зливається.

Наступна лаба: git checkout main → git checkout -b Lab-03. З Лаби 03 починається основний проєкт ClinicApp/, і її гілка вже зливається в main.

Розроблено Tomka Yurii · © 2026 ·