Словари и хеш-таблицы в C# (.NET 6): подробное руководство
Словари и хеш-таблицы в C#
Что такое словарь и зачем он нужен?
Представь, что у тебя есть волшебная записная книжка. В обычной записной книжке ты можешь записать имя друга и его номер телефона. Когда тебе нужно позвонить, ты ищешь имя в книжке и смотришь номер. Словарь в программировании работает точно так же!
Словарь (Dictionary) — это коллекция, которая хранит пары "ключ — значение". Ключ — это то, по чему мы ищем (например, имя друга), а значение — это то, что мы ищем (номер телефона).
Главное преимущество словаря — очень быстрый поиск. Неважно, хранится в словаре 10 записей или 10 000 — поиск по ключу происходит практически мгновенно. Это возможно благодаря особой структуре данных, которая называется хеш-таблица.
Как создать и использовать словарь
В C# словарь называется Dictionary, где TKey — это тип ключа, а TValue — тип значения.
// Создаём пустой словарь, где ключ — строка (имя), значение — строка (номер телефона)
Dictionary<string, string> phoneBook = new Dictionary<string, string>();
// Добавляем записи
phoneBook.Add("Аня", "+7-912-345-67-89");
phoneBook.Add("Петя", "+7-923-456-78-90");
// Получаем значение по ключу
string petePhone = phoneBook["Петя"];
Console.WriteLine($"Телефон Пети: {petePhone}");
// Проверяем, есть ли ключ в словаре
if (phoneBook.ContainsKey("Аня"))
{
Console.WriteLine("Аня есть в справочнике!");
}
// Изменяем значение
phoneBook["Аня"] = "+7-999-888-77-66";
// Удаляем запись
phoneBook.Remove("Петя");
Другой способ создания словаря
Можно сразу создать словарь с начальными данными:
Dictionary<string, string> greetings = new Dictionary<string, string>()
{
{ "Россия", "Здравствуйте!" },
{ "Франция", "Bonjour!" },
{ "Италия", "Ciao!" },
{ "Англия", "Hello!" }
};
Console.WriteLine($"В Англии говорят: {greetings["Англия"]}");
Перебор всех элементов словаря
Чтобы пройтись по всем записям словаря, используем цикл foreach. Каждый элемент — это пара KeyValuePair, у которой есть свойства Key и Value.
Dictionary<string, int> products = new Dictionary<string, int>()
{
{ "Хлеб", 45 },
{ "Молоко", 80 },
{ "Яблоки", 120 }
};
Console.WriteLine("Наши товары:");
foreach (var item in products)
{
Console.WriteLine($"{item.Key} стоит {item.Value} рублей");
}
Вывод программы:
Наши товары:
Хлеб стоит 45 рублей
Молоко стоит 80 рублей
Яблоки стоит 120 рублей
Словарь со списком значений
Иногда нужно, чтобы у одного ключа было несколько значений. Например, для каждого дня недели — список дел. Для этого можно использовать словарь, где значение — это список (List).
// Словарь, где ключ — день недели, значение — список дел
Dictionary<string, List<string>> weeklyPlan = new Dictionary<string, List<string>>();
// Добавляем список дел на понедельник
weeklyPlan["Понедельник"] = new List<string>() { "Сделать уроки", "Покормить кота" };
// Добавляем ещё одно дело в понедельник
weeklyPlan["Понедельник"].Add("Почитать книгу");
// Добавляем вторник
weeklyPlan["Вторник"] = new List<string>() { "Сходить в бассейн" };
// Выводим все дела на понедельник
Console.WriteLine("Дела на понедельник:");
foreach (string task in weeklyPlan["Понедельник"])
{
Console.WriteLine($"- {task}");
}
Разбор типичных задач
Задача 1: Телефонный справочник
Нужно найти номер телефона по имени. Если имени нет — сообщить об этом.
Dictionary<string, string> phoneBook = new Dictionary<string, string>()
{
{ "Маша", "8-912-345-67-89" },
{ "Саша", "8-923-456-78-90" },
{ "Даша", "8-934-567-89-01" }
};
Console.Write("Введите имя для поиска: ");
string name = Console.ReadLine();
if (phoneBook.ContainsKey(name))
{
Console.WriteLine($"Номер телефона {name}: {phoneBook[name]}");
}
else
{
Console.WriteLine("Такого имени нет в справочнике");
}
Задача 2: Удаление контакта
Пользователь вводит имя, и программа удаляет этот контакт из словаря.
Dictionary<string, string> contacts = new Dictionary<string, string>()
{
{ "Иван", "8-111-222-33-44" },
{ "Мария", "8-555-666-77-88" },
{ "Алексей", "8-999-000-11-22" }
};
Console.Write("Введите имя контакта для удаления: ");
string nameToDelete = Console.ReadLine();
if (contacts.Remove(nameToDelete))
{
Console.WriteLine($"Контакт '{nameToDelete}' удалён!");
}
else
{
Console.WriteLine($"Контакта '{nameToDelete}' не существует");
}
// Показываем оставшиеся контакты
Console.WriteLine("Оставшиеся контакты:");
foreach (var contact in contacts)
{
Console.WriteLine($"{contact.Key}: {contact.Value}");
}
Задача 3: Вывод всех ключей словаря
Программа выводит список всех товаров (только названия) из словаря.
Dictionary<string, int> store = new Dictionary<string, int>()
{
{ "Яблоки", 150 },
{ "Бананы", 120 },
{ "Апельсины", 180 },
{ "Виноград", 250 }
};
Console.WriteLine("Список доступных товаров:");
foreach (string productName in store.Keys) // Keys — это коллекция всех ключей
{
Console.WriteLine($"- {productName}");
}
Частые ошибки новичков
Ошибка 1: Обращение к несуществующему ключу
Dictionary<string, int> ages = new Dictionary<string, int>();
ages["Вася"] = 10;
// Ошибка! Ключа "Петя" нет в словаре
// Console.WriteLine(ages["Петя"]); // Вызовет исключение!
// Правильно: сначала проверить
if (ages.ContainsKey("Петя"))
{
Console.WriteLine(ages["Петя"]);
}
Ошибка 2: Добавление дублирующегося ключа
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("Ключ", "Значение 1");
// dict.Add("Ключ", "Значение 2"); // Ошибка! Ключ уже существует
// Правильно: использовать индексатор для замены значения
dict["Ключ"] = "Новое значение"; // Перезаписывает старое значение
Ошибка 3: Путаница между ключом и значением
Dictionary<int, string> numbers = new Dictionary<int, string>();
numbers.Add(1, "Один");
numbers.Add(2, "Два");
// Ключ — это число, значение — строка
// numbers.Add("Три", 3); // Ошибка! Типы перепутаны
Итоговый пример: Программа для заметок
Давай напишем программу, которая объединяет все изученные приёмы. Это будет простой цифровой блокнот:
Dictionary<string, string> notebook = new Dictionary<string, string>();
Console.WriteLine("=== Цифровой блокнот ===");
Console.WriteLine("1 - Добавить контакт");
Console.WriteLine("2 - Найти контакт");
Console.WriteLine("3 - Удалить контакт");
Console.WriteLine("4 - Показать все контакты");
Console.WriteLine("5 - Выйти");
while (true)
{
Console.Write("\nВыберите действие: ");
string choice = Console.ReadLine();
if (choice == "1")
{
Console.Write("Введите имя: ");
string name = Console.ReadLine();
Console.Write("Введите номер телефона: ");
string phone = Console.ReadLine();
if (notebook.ContainsKey(name))
{
Console.WriteLine("Контакт с таким именем уже существует! Обновляем номер...");
}
notebook[name] = phone;
Console.WriteLine("Контакт сохранён!");
}
else if (choice == "2")
{
Console.Write("Введите имя для поиска: ");
string name = Console.ReadLine();
if (notebook.TryGetValue(name, out string phone))
{
Console.WriteLine($"Телефон {name}: {phone}");
}
else
{
Console.WriteLine("Контакт не найден");
}
}
else if (choice == "3")
{
Console.Write("Введите имя для удаления: ");
string name = Console.ReadLine();
if (notebook.Remove(name))
{
Console.WriteLine($"Контакт '{name}' удалён!");
}
else
{
Console.WriteLine("Такого контакта нет");
}
}
else if (choice == "4")
{
if (notebook.Count == 0)
{
Console.WriteLine("Блокнот пуст");
}
else
{
Console.WriteLine("Все контакты:");
foreach (var entry in notebook)
{
Console.WriteLine($"{entry.Key}: {entry.Value}");
}
}
}
else if (choice == "5")
{
Console.WriteLine("До свидания!");
break;
}
else
{
Console.WriteLine("Неверный выбор, попробуйте снова");
}
}
В этом примере мы использовали:
Dictionaryдля хранения пар "имя — телефон"ContainsKeyдля проверки существования ключаTryGetValueдля безопасного получения значенияRemoveдля удаления элементаCountдля проверки количества элементовforeachдля перебора всех записей
Словари — это мощный и удобный инструмент, который ты будешь использовать в своих программах очень часто. Они помогают хранить данные в понятном виде и быстро находить нужную информацию!