3_Массивы и Коллекции

Урок 3 : Массивы и Коллекции

О чём этот урок

Когда данных много - одной переменной недостаточно. Массивы и коллекции позволяют хранить наборы значений и эффективно работать с ними.


1. Массивы (Array)

Массив - это как пронумерованные ячейки в шкафчиках раздевалки: количество ячеек фиксировано при создании, и к каждой обращаются по номеру (индексу).

Упорядоченный набор элементов одного типа с фиксированным размером. Размер задаётся при создании и не меняется.

// Объявление и создание массива из 5 элементов
int[] scores = new int[5];          // все элементы = 0 по умолчанию

// Объявление с инициализацией
int[] damage = { 10, 25, 7, 42, 18 };

// Явный синтаксис
string[] names = new string[] { "Артём", "Мария", "Иван" };

// Доступ по индексу (нумерация с 0!)
Console.WriteLine(damage[0]);  // 10 - первый элемент
Console.WriteLine(damage[4]);  // 18 - последний
damage[2] = 99;                // изменить элемент

// Длина массива
Console.WriteLine(damage.Length); // 5
Индексы начинаются с 0

Первый элемент - arr[0], последний - arr[arr.Length - 1]. Обращение к arr[arr.Length] вызовет IndexOutOfRangeException.

Перебор массива

int[] numbers = { 5, 3, 8, 1, 9 };

// Через for - когда нужен индекс
for (int i = 0; i < numbers.Length; i++)
{
    Console.WriteLine($"[{i}] = {numbers[i]}");
}

// Через foreach - когда индекс не нужен
foreach (int num in numbers)
{
    Console.Write(num + " ");
}

Полезные методы для массивов

int[] arr = { 5, 3, 8, 1, 9 };

Array.Sort(arr);              // сортировка по возрастанию: 1, 3, 5, 8, 9
Array.Reverse(arr);           // разворот: 9, 8, 5, 3, 1
int idx = Array.IndexOf(arr, 5);  // найти индекс элемента со значением 5 в массиве arr
Array.Fill(arr, 0);           // заполнить все элементы массива arr значением 0

Многомерные массивы

// Двумерный массив (матрица 3x3)
int[,] grid = new int[3, 3];
grid[0, 0] = 1;
grid[1, 2] = 5;

// Инициализация
int[,] matrix = {
    { 1, 2, 3 },
    { 4, 5, 6 },
    { 7, 8, 9 }
};

Console.WriteLine(matrix[1, 1]); // 5 - центр матрицы

// Перебор
for (int row = 0; row < matrix.GetLength(0); row++)
{
    for (int col = 0; col < matrix.GetLength(1); col++)
    {
        Console.Write(matrix[row, col] + " ");
    }
    Console.WriteLine();
}

2. Коллекции. Чем они отличаются от массива?

Характеристика Массив Т[] Коллекция (напр. List<Т>)
Размер Фиксированный Динамический
Добавление элементов Невозможно без пересоздания Просто: Add(), Insert()
Удаление элементов Нельзя Просто: Remove(), RemoveAt()
Производительность Чуть быстрее при прямом доступе Небольшие накладные расходы
Функциональность Минимальная Богатый API
Правило выбора

  • Знаете размер заранее и он не меняется → Array
  • Размер неизвестен или изменяется → List<Т>
  • Нужен поиск по ключу → Dictionary<ТKey, ТValue>


3. List<Т> - динамический список

List<Т> напоминает список покупок: можно добавлять позиции в любом месте, вычёркивать их, и список сам подстраивает свой размер.

Хранит элементы одного типа в порядке добавления. Самая используемая коллекция.

using System.Collections.Generic;

// Создание
List<int> scores = new List<int>();
List<string> players = new List<string> { "Артём", "Мария" };

// Добавление
scores.Add(100);           // в конец
scores.Add(200);
scores.Insert(0, 50);      // по индексу: 50, 100, 200

// Доступ
Console.WriteLine(scores[0]);    // 50
Console.WriteLine(scores.Count); // 3 (не Length, а Count!)

// Поиск
bool has = scores.Contains(100); // true
int idx  = scores.IndexOf(200);  // 2

// Удаление
scores.Remove(100);         // удалить первое вхождение значения
scores.RemoveAt(0);         // удалить по индексу

// Сортировка
scores.Sort();              // по возрастанию
scores.Reverse();           // разворот

// Очистка
scores.Clear();

Перебор List

List<string> weapons = new List<string> { "Меч", "Лук", "Посох" };

foreach (string w in weapons)
    Console.WriteLine(w);

// С индексом через for
for (int i = 0; i < weapons.Count; i++)
    Console.WriteLine($"{i}: {weapons[i]}");
List в Unity

В Unity List<Т> используется повсюду: список врагов, инвентарь предметов, очередь событий. Это стандартный инструмент для любого динамического набора объектов.


4. Dictionary<ТKey, ТValue> - словарь

Dictionary - как записная книжка: открываете по имени контакта и сразу видите его номер телефона. Хранит пары ключ / значение, ключи уникальны, поиск по ключу мгновенный (O(1)).

// Создание
Dictionary<string, int> stats = new Dictionary<string, int>();
Dictionary<int, string> months = new Dictionary<int, string>
{
    { 1, "Январь" },
    { 2, "Февраль" },
    { 3, "Март" }
};

// Добавление
stats["strength"] = 15;
stats["agility"]  = 12;
stats.Add("intelligence", 8);  // Add бросит исключение, если ключ уже есть

// Доступ
Console.WriteLine(stats["strength"]); // 15
Console.WriteLine(months[2]);         // Февраль

// Безопасный доступ (без исключения если ключ отсутствует)
if (stats.TryGetValue("luck", out int luckValue))
    Console.WriteLine($"Удача: {luckValue}");
else
    Console.WriteLine("Ключ не найден");

// Проверка наличия ключа
bool hasKey = stats.ContainsKey("agility");     // true
bool hasVal = stats.ContainsValue(15);           // true

// Изменение
stats["agility"] = 20;

// Удаление
stats.Remove("intelligence");

// Количество
Console.WriteLine(stats.Count);

Перебор Dictionary

// Перебор пар ключ-значение
foreach (KeyValuePair<string, int> pair in stats)
{
    Console.WriteLine($"{pair.Key}: {pair.Value}");
}

// Краткая запись с var
foreach (var pair in stats)
    Console.WriteLine($"{pair.Key} = {pair.Value}");

// Только ключи
foreach (string key in stats.Keys)
    Console.WriteLine(key);

// Только значения
foreach (int val in stats.Values)
    Console.WriteLine(val);
Порядок элементов в Dictionary

Dictionary не гарантирует порядок перебора. Если нужен упорядоченный словарь - используйте SortedDictionary<ТKey, ТValue>.


Для углублённого изучения

HashSet<Т> - множество уникальных элементов

HashSet<Т> хранит только уникальные значения (дубликаты игнорируются). Очень быстрая проверка наличия элемента (O(1)).

HashSet<string> tags = new HashSet<string>();

tags.Add("fire");
tags.Add("magic");
tags.Add("fire");   // дубликат - игнорируется!

Console.WriteLine(tags.Count);        // 2
Console.WriteLine(tags.Contains("fire")); // true - мгновенная проверка

// Операции над множествами
HashSet<int> setA = new HashSet<int> { 1, 2, 3, 4 };
HashSet<int> setB = new HashSet<int> { 3, 4, 5, 6 };

setA.IntersectWith(setB);  // Пересечение: { 3, 4 }
setA.UnionWith(setB);      // Объединение: { 1, 2, 3, 4, 5, 6 }
setA.ExceptWith(setB);     // Разность: { 1, 2 }
Когда использовать HashSet

  • Проверка, встречался ли уже этот элемент (посещённые комнаты, собранные предметы)
  • Исключение дубликатов из набора
  • Когда List.Contains() работает слишком медленно на больших данных

Сравнение коллекций

Коллекция Уникальность Порядок Доступ Когда использовать
List<T> Нет Да По индексу Упорядоченный список
Dictionary<К,V> По ключу Нет По ключу Пары ключ-значение
HashSet<T> Да Нет Нет Уникальные элементы

Итог урока


📋 Перейти к практическим заданиям урока 3

Материалы для дополнительного ознакомления :

Массивы
Класс Array
Список
Словарь