0Pricing
C# Academy · Урок

Поиск в словарях

Быстрый доступ по ключу и значению.

«Поиск в словарях» — бесплатный урок 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 — локальная установка не требуется.

Все уроки этого курса

  1. Списки на практике
  2. Поиск в словарях
  3. HashSet и уникальность
  4. Выбор коллекции
← Назад к C# Academy