Поиск в словарях
Быстрый доступ по ключу и значению.
«Поиск в словарях» — бесплатный урок C# Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.
Пары ключ–значение
Dictionary<TKey, TValue> сопоставляет уникальные ключи со значениями. Представьте его как таблицу поиска: передайте ключ и быстро получите значение.
В основе этого типа лежит хеш-таблица, поэтому поиск значения по ключу в среднем выполняется за O(1), что значительно быстрее просмотра списка.
using System.Collections.Generic;
var ages = new Dictionary<string, int>();
ages["Ann"] = 30;
ages["Bob"] = 25;Инициализация словаря
Заполнить словарь начальными значениями можно с помощью инициализатора коллекции. Каждая запись связывает ключ с его значением.
Ключи должны быть уникальными. Если дважды указать один и тот же ключ в инициализаторе, во время выполнения возникнет ArgumentException.
using System;
using System.Collections.Generic;
class Program {
static void Main() {
var caps = new Dictionary<string, string> {
["FR"] = "Paris",
["JP"] = "Tokyo"
};
Console.WriteLine(caps["JP"]);
}
}Чтение по ключу
Используйте индексатор для чтения: dict[key]. В среднем это O(1).
Но будьте осторожны: если ключ отсутствует, индексатор выдаёт исключение KeyNotFoundException. Чтение по отсутствующему ключу — одна из самых распространённых ошибок при работе со словарями.
var ages = new Dictionary<string, int> { ["Ann"] = 30 };
int a = ages["Ann"]; // 30
// int b = ages["Zoe"]; // throws KeyNotFoundExceptionБезопасный поиск с помощью TryGetValue
TryGetValue позволяет избежать исключений. Он возвращает true и задаёт переменную out, если ключ существует, или false в противном случае.
Это идиоматичный способ без выделения памяти для поиска значения, наличие которого не гарантировано.
using System;
using System.Collections.Generic;
class Program {
static void Main() {
var ages = new Dictionary<string, int> { ["Ann"] = 30 };
if (ages.TryGetValue("Ann", out int v))
Console.WriteLine(v);
}
}ContainsKey и значения по умолчанию
ContainsKey проверяет наличие ключа, не извлекая значение, за O(1). Используйте его перед чтением через индексатор, если вам нужно только получить ответ «да» или «нет».
Если вызвать и ContainsKey, и индексатор, хеш ключа вычисляется дважды. TryGetValue делает это один раз, поэтому обычно работает быстрее.
var ages = new Dictionary<string, int> { ["Ann"] = 30 };
if (ages.ContainsKey("Ann"))
System.Console.WriteLine(ages["Ann"]);Добавление и присваивание
Индексатор dict[key] = value добавляет новую пару или перезаписывает существующую. Add(key, value) только добавляет пару и выдаёт исключение, если такой ключ уже существует.
Используйте Add, когда дублирующийся ключ должен считаться ошибкой, а индексатор — когда перезапись допустима.
using System;
using System.Collections.Generic;
class Program {
static void Main() {
var d = new Dictionary<string, int>();
d["x"] = 1;
d["x"] = 2; // overwrite, fine
Console.WriteLine(d["x"]);
}
}Удаление записей
Remove(key) удаляет пару и в среднем за O(1) возвращает true, если ключ присутствовал.
У этого метода есть перегрузка, возвращающая удалённое значение через параметр out. Это удобно, когда нужно за один шаг удалить значение и использовать его.
var d = new Dictionary<string, int> { ["a"] = 1, ["b"] = 2 };
bool removed = d.Remove("a"); // true
bool again = d.Remove("a"); // falseПеребор пар
Цикл возвращает элементы KeyValuePair<TKey, TValue>. Деструктурируйте их в ключ и значение, чтобы код оставался ясным.
Порядок перечисления не гарантируется: никогда не полагайтесь на порядок добавления записей. Используйте Keys или Values, чтобы перебирать только одну сторону пары.
using System;
using System.Collections.Generic;
class Program {
static void Main() {
var d = new Dictionary<string, int> { ["a"] = 1, ["b"] = 2 };
foreach (var (key, val) in d)
Console.WriteLine($"{key}={val}");
}
}Подсчёт с помощью словаря
Классический пример применения — подсчёт вхождений. Для каждого элемента увеличивайте его счётчик, начиная с нуля, если элемент встретился впервые.
Для n элементов этот шаблон работает за O(n), потому что каждый поиск и обновление выполняются за O(1), тогда как при каждом проходе по списку получилось бы O(n²).
using System;
using System.Collections.Generic;
class Program {
static void Main() {
var counts = new Dictionary<char, int>();
foreach (char c in "banana")
counts[c] = counts.GetValueOrDefault(c) + 1;
Console.WriteLine(counts['a']);
}
}Равенство ключей имеет значение
Поиск опирается на GetHashCode и Equals типа ключа. Встроенные типы и string работают без дополнительной настройки.
Для ключей пользовательских классов переопределите оба метода или используйте record. Иначе два внешне одинаковых ключа будут иметь разные хеши, и поиск завершится неудачей.
var byName = new Dictionary<string, int>(
System.StringComparer.OrdinalIgnoreCase);
byName["Hi"] = 1;
bool found = byName.ContainsKey("HI"); // trueВыбор типа значения
Значениями могут быть любые объекты, в том числе списки. Dictionary<string, List<int>> группирует множество значений по одному ключу.
При добавлении в такую структуру создайте вложенный список при первом использовании, а затем добавьте в него значение. Так строится сгруппированная карта с несколькими значениями.
var groups = new Dictionary<string, List<int>>();
void Add(string k, int v) {
if (!groups.TryGetValue(k, out var list))
groups[k] = list = new List<int>();
list.Add(v);
}Быстрая проверка
Выберите самый безопасный способ прочитать ключ, который может отсутствовать.
Итоги
Dictionary<K,V> обеспечивает в среднем поиск, добавление и удаление по ключу за O(1), используя хеш-таблицу.
Предпочитайте TryGetValue индексатору, выбрасывающему исключение, поддерживайте уникальность ключей и убедитесь, что пользовательские типы ключей реализуют корректное сравнение на равенство и хеширование. Порядок перебора не определён.
Часто задаваемые вопросы
Урок «Поиск в словарях» бесплатный?
Да — полный текст урока «Поиск в словарях» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.
Чему я научусь в уроке «Поиск в словарях»?
Быстрый доступ по ключу и значению. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C# Academy?
Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Поиск в словарях»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C# Academy?
Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Списки на практике
- Поиск в словарях
- HashSet и уникальность
- Выбор коллекции