Avatar ·

Как перебрать (итерировать) все элементы словаря Dictionary в C#?

Привет, коллеги! Только начал изучать C# и столкнулся с такой проблемой. У меня есть объект Dictionary, который хранит имена студентов и их оценки. Мне нужно вывести на консоль все пары ключ-значение. Я понимаю, что словарь — это не массив и не список, поэтому обычный цикл for с индексом тут не сработает. Перепробовал несколько вариантов: пытался использовать foreach, но не знаю, как правильно обращаться к элементам. Пробовал что-то вроде foreach (var item in myDictionary), но внутри цикла не понимаю, как получить ключ и значение по отдельности. Вот пример моего кода: ```csharp Dictionary students = new Dictionary { { "Анна", 85 }, { "Борис", 92 }, { "Виктор", 78 } }; // Как мне теперь вывести всех студентов и их оценки? // Пытался так, но это не работает: foreach (var entry in students) { Console.WriteLine(entry.Key + ": " + entry.Value); // Ошибка: нет такого свойства? } ``` Подскажите, пожалуйста, какой правильный синтаксис для перебора словаря? И есть ли другие способы, кроме foreach? Заранее спасибо! <<>>

Основной способ: перебор через KeyValuePair

В C# словарь Dictionary<TKey, TValue> реализует интерфейс IEnumerable<KeyValuePair<TKey, TValue>>. Это значит, что при использовании foreach каждый элемент цикла будет иметь тип KeyValuePair<TKey, TValue>, у которого есть свойства Key и Value. Ваш код был почти правильным, но нужно явно указать тип переменной или использовать var.

Вот исправленный пример:

Dictionary<string, int> students = new Dictionary<string, int>
{
    { "Анна", 85 },
    { "Борис", 92 },
    { "Виктор", 78 }
};

// Вариант 1: явное указание типа
foreach (KeyValuePair<string, int> entry in students)
{
    Console.WriteLine($"{entry.Key}: {entry.Value}");
}

// Вариант 2: с var (компилятор сам подставит тип)
foreach (var entry in students)
{
    Console.WriteLine($"{entry.Key}: {entry.Value}");
}

Альтернативные способы перебора

  • Перебор только ключей — используйте свойство Keys:
foreach (string name in students.Keys)
{
    Console.WriteLine($"{name}: {students[name]}");
}
  • Перебор только значений — свойство Values:
foreach (int grade in students.Values)
{
    Console.WriteLine($"Оценка: {grade}");
}
  • Метод ForEach (только для списков) — для словарей напрямую не работает, но можно преобразовать в список:
students.ToList().ForEach(entry => Console.WriteLine($"{entry.Key}: {entry.Value}"));

Важные замечания

1. Не изменяйте словарь во время перебора — добавление или удаление элементов внутри цикла foreach вызовет исключение InvalidOperationException. Если нужно модифицировать словарь, соберите ключи в отдельный список:

List<string> keysToRemove = new List<string>();
foreach (var entry in students)
{
    if (entry.Value < 80)
        keysToRemove.Add(entry.Key);
}
foreach (string key in keysToRemove)
    students.Remove(key);

2. Порядок элементов — в обычном Dictionary порядок не гарантирован. Если важен порядок добавления, используйте OrderedDictionary (из System.Collections.Specialized) или SortedDictionary.

3. Производительность — перебор через foreach по словарю очень быстрый (O(n)). Для больших словарей избегайте обращения по ключу внутри цикла (например, students[key]), если ключ уже есть в entry.Key — это лишний поиск.

Таким образом, самый простой и читаемый способ — использовать foreach (var entry in dictionary) и обращаться к entry.Key и entry.Value. Этот подход работает во всех версиях C#, начиная с .NET Framework 2.0.

<<>>

Использование LINQ для гибкого перебора

Если вам нужно не просто вывести все элементы, а выполнить фильтрацию, проекцию или сортировку, удобно использовать LINQ. Методы расширения работают со словарём как с коллекцией пар «ключ-значение».

Примеры:

using System.Linq;

// Вывести только студентов с оценкой выше 80
var highGrades = students.Where(kvp => kvp.Value > 80);
foreach (var entry in highGrades)
    Console.WriteLine($"{entry.Key}: {entry.Value}");

// Получить отсортированный список по имени
var sorted = students.OrderBy(kvp => kvp.Key);
foreach (var entry in sorted)
    Console.WriteLine($"{entry.Key}: {entry.Value}");

// Преобразовать в список строк
List<string> result = students
    .Select(kvp => $"{kvp.Key} - {kvp.Value}")
    .ToList();

LINQ-запросы выполняются лениво (отложенное выполнение), поэтому если вы планируете перебирать результат несколько раз, лучше материализовать его через .ToList() или .ToArray(). Это особенно важно, если исходный словарь может измениться между проходами.

Также обратите внимание на метод TryGetValue — он безопаснее, чем обращение через индексатор, если ключа может не быть:

if (students.TryGetValue("Анна", out int grade))
    Console.WriteLine($"Анна: {grade}");
else
    Console.WriteLine("Студент не найден");

LINQ даёт большую гибкость, но для простого перебора лучше использовать классический foreach — он читается легче и не требует дополнительных using-директив.