Перебирать ключи словаря C# с индексом?

Как выполнить итерацию по ключам словаря при сохранении индекса ключа. Что я сделал слияние foreach - цикл с локальной переменной i, который увеличивается на единицу для каждого витка цикла.

вот мой код, который работает:

public IterateOverMyDict()
{
    int i=-1;
    foreach (string key in myDict.Keys)
    {
        i++;
        Console.Write(i.ToString() + " : " + key);
    }
}

однако использование локальной переменной i. Мне было интересно, есть ли способ, когда мне не нужно использовать "дополнительную" переменную? Не говоря, что это плохой путь, но есть ли лучший? один?

5 ответов


нет такого понятия, как "индекс ключа". Вы всегда должны лечить Dictionary<TKey, TValue> как имеющий непредсказуемый порядок-где порядок, который вы чтобы получить при итерации по нему может измениться. (Таким образом, теоретически, вы можете добавить одну новую запись,и записи могут быть в совершенно другом порядке в следующий раз, когда вы повторите их. Теоретически это может даже произойти без вы меняете данные, но это менее вероятно в нормальных реализации.)

если вы действительно хотите получить числовой индекс, который вы наблюдали на этот раз, вы можете использовать:

foreach (var x in dictionary.Select((Entry, Index) => new { Entry, Index }))
{
    Console.WriteLine("{0}: {1} = {2}", x.Index, x.Entry.Key, x.Entry.Value);
}

... но имейте в виду, что это довольно вводящий в заблуждение дисплей, поскольку он предполагает неотъемлемый порядок.

С документация:

для целей перечисления, каждый элемент в словаре трактуется как KeyValuePair<TKey, TValue> структура, представляющая значение и его ключ. Этот порядок, в котором возвращается неопределено.

EDIT: Если вам не нравится Select звони сюда, ты мог бы создать свой собственный метод расширения:

public struct IndexedValue<T>
{
    private readonly T value;
    private readonly int index;

    public T Value { get { return value; } }
    public int Index { get { return index; } }

    public IndexedValue(T value, int index)
    {
        this.value = value;
        this.index = index;
    }
}

public static class Extensions
{
    public static IEnumerable<IndexedValue<T>> WithIndex<T>
        (this IEnumerable<T> source)
    {
        return source.Select((value, index) => new IndexedValue<T>(value, index));
    }
}

тогда ваш цикл будет:

foreach (var x in dictionary.WithIndex())
{
    Console.WriteLine("{0}: {1} = {2}", x.Index, x.Value.Key, x.Value.Value);
}

технически ключом является индекс в Dictionary<TKey, TValue>. Вы не гарантированно получите элементы в определенном порядке, поэтому на самом деле нет никакого числового индекса.


Не совсем так. Обратите внимание, что ключи в словаре не являются логически "упорядоченными". У них нет указателя. С точки зрения словаря, нет ни первого, ни последнего ключа. Вы можете самостоятельно отслеживать, является ли это первым ключом, возвращаемым перечислителем, как вы это делаете, но в словаре нет понятия "дайте мне 5-й ключ", поэтому вы не можете использовать for цикл с индексатором, как вы могли бы со списком или массивом.


словари не совсем списки, массивы или векторы. Они делают еще один шаг вперед. Ключом может быть индекс:

Dictionary myDictionary<int, string> = new Dictionary<int, string>()
{
    {0, "cat"},
    {1, "dog"},
    {2, "pig"},
    {3, "horse"}
};
myDictionary[4] = "hat";

for int i = 0; i <5; i++){
    Console.Writeline(myDictionary[i]);
}

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


подход Select((Entry, Index) => new { Entry, Index}), вероятно, лучше всего в конкретном контексте этого вопроса, но, как альтернатива, система.В LINQ.Enumerable теперь позволяет конвертировать словарь в список. Что-то вроде этого сработает:

var x = dictionary.ToList();
for (int y=0; y<x.Count; y++) Console.WriteLine(y + " = " + x[y].Key);

есть плюсы и минусы обоих подходов, в зависимости от того, что вы пытаетесь сделать.