Доступ к Dictionary.Keys ключа с помощью числового индекса

голоса
136

Я использую Dictionary<string, int>где intэто подсчет ключа.

Теперь мне нужно получить доступ к последнему вставленному ключу внутри словаря, но я не знаю название. Очевидная попытка:

int LastCount = mydict[mydict.keys[mydict.keys.Count]];

не работает, потому что Dictionary.Keysне реализует [] -indexer.

Мне просто интересно , если есть аналогичный класс? Я думал об использовании стека, но хранит только строки. Теперь я мог создать свою собственную - структуру , а затем использовать Stack<MyStruct>, но мне интересно , если есть другая альтернатива, по существу, словарь , который реализует [] -indexer на клавишах?

Задан 07/08/2008 в 01:51
источник пользователем
На других языках...                            


15 ответов

голоса
6

Вы всегда можете сделать это:

string[] temp = new string[mydict.count];
mydict.Keys.CopyTo(temp, 0)
int LastCount = mydict[temp[mydict.count - 1]]

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

Ответил 07/08/2008 в 02:13
источник пользователем

голоса
2

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

Единственное, что я могу думать о том, чтобы хранить ключи в списке поиска и добавить ключи в список, прежде чем добавить их в словарь ... это не очень Тхо.

Ответил 07/08/2008 в 02:15
источник пользователем

голоса
5

Я думаю, что вы можете сделать что-то вроде этого, синтаксис может быть неправильным, нету используется C # в то время, чтобы получить последний элемент

Dictionary<string, int>.KeyCollection keys = mydict.keys;
string lastKey = keys.Last();

или использовать Максы вместо Последнего получить максимальное значение, я не знаю, какой из них подходит для вашего кода лучше.

Ответил 07/08/2008 в 02:18
источник пользователем

голоса
4

Я согласен со второй частью ответа Патрика. Даже если в некоторых тестах, кажется, сохранить порядок вставки, документация (и нормальное поведение для словарей и хэш) четко говорятся упорядочение неопределенное.

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

Ответил 07/08/2008 в 03:38
источник пользователем

голоса
3

То, как вы сформулировали вопрос заставляет меня верить, что ИНТ в словаре содержит «положение» элемента по словарю. Судя по утверждению, что ключи не хранятся в том порядке, что они добавляют, если это правильно, это будет означать, что keys.Count (или .Count - 1, если вы используете с нуля), должны по-прежнему всегда будет номер последней введенной клавиши?

Если это верно, есть ли причина, вы не можете использовать вместо Dictionary <INT, строка>, так что вы можете использовать mydict [mydict.Keys.Count]?

Ответил 07/08/2008 в 03:40
источник пользователем

голоса
8

Почему вы не просто расширить класс словаря для добавления в последнем ключе вставленной собственности. Что-то вроде следующего, может быть?

public class ExtendedDictionary : Dictionary<string, int>
{
    private int lastKeyInserted = -1;

    public int LastKeyInserted
    {
        get { return lastKeyInserted; }
        set { lastKeyInserted = value; }
    }

    public void AddNew(string s, int i)
    {
        lastKeyInserted = i;

        base.Add(s, i);
    }
}
Ответил 07/08/2008 в 12:15
источник пользователем

голоса
56

Вы можете использовать OrderedDictionary .

Представляет коллекцию пар ключ / значение, которые доступны с помощью ключа или индекса.

Ответил 08/08/2008 в 02:23
источник пользователем

голоса
16

Словарь является хэш-таблицы, поэтому вы не имеете ни малейшего представления о порядке вставки!

Если вы хотите узнать последний вставленный ключ я предложил бы расширить словарь включить LastKeyInserted значения.

Например:

public MyDictionary<K, T> : IDictionary<K, T>
{
    private IDictionary<K, T> _InnerDictionary;

    public K LastInsertedKey { get; set; }

    public MyDictionary()
    {
        _InnerDictionary = new Dictionary<K, T>();
    }

    #region Implementation of IDictionary

    public void Add(KeyValuePair<K, T> item)
    {
        _InnerDictionary.Add(item);
        LastInsertedKey = item.Key;

    }

    public void Add(K key, T value)
    {
        _InnerDictionary.Add(key, value);
        LastInsertedKey = key;
    }

    .... rest of IDictionary methods

    #endregion

}

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

Ответил 16/04/2009 в 15:09
источник пользователем

голоса
3

В случае , если вы решили использовать опасный код , который подлежит к обрыву, эта функция расширения будет получать ключ от в Dictionary<K,V>соответствии с его внутренней индексацией (которая для Mono и .NET в настоящее время , как представляется, в том же порядке , как вы получите, перечисляя Keysимущество ).

Намного предпочтительнее использовать Linq: dict.Keys.ElementAt(i), но эта функция будет итерацию O (N); следующее O (1) , но с потерей производительности отражения.

using System;
using System.Collections.Generic;
using System.Reflection;

public static class Extensions
{
    public static TKey KeyByIndex<TKey,TValue>(this Dictionary<TKey, TValue> dict, int idx)
    {
        Type type = typeof(Dictionary<TKey, TValue>);
        FieldInfo info = type.GetField("entries", BindingFlags.NonPublic | BindingFlags.Instance);
        if (info != null)
        {
            // .NET
            Object element = ((Array)info.GetValue(dict)).GetValue(idx);
            return (TKey)element.GetType().GetField("key", BindingFlags.Public | BindingFlags.Instance).GetValue(element);
        }
        // Mono:
        info = type.GetField("keySlots", BindingFlags.NonPublic | BindingFlags.Instance);
        return (TKey)((Array)info.GetValue(dict)).GetValue(idx);
    }
};
Ответил 12/04/2010 в 05:44
источник пользователем

голоса
204

Как @Falanwe отмечает в комментарии, делать что - то , как это неправильно :

int LastCount = mydict.Keys.ElementAt(mydict.Count -1);

Вы не должны зависеть от порядка ключей в словаре. Если вам нужен заказ, вы должны использовать OrderedDictionary , как предложено в этом ответе . Другие ответы на этой странице интересны также.

Ответил 19/01/2011 в 14:21
источник пользователем

голоса
4

Один из вариантов будет KeyedCollection , если ключ встроен в значение.

Просто создать базовую реализацию в запечатанном классе для использования.

Таким образом , чтобы заменить Dictionary<string, int>(что не очень хороший пример , поскольку не ясно , ключ для междунар).

private sealed class IntDictionary : KeyedCollection<string, int>
{
    protected override string GetKeyForItem(int item)
    {
        // The example works better when the value contains the key. It falls down a bit for a dictionary of ints.
        return item.ToString();
    }
}

KeyedCollection<string, int> intCollection = new ClassThatContainsSealedImplementation.IntDictionary();

intCollection.Add(7);

int valueByIndex = intCollection[0];
Ответил 20/07/2011 в 01:45
источник пользователем

голоса
2

Для того, чтобы расширить свое присутствие на Daniels пост и его комментарии относительно ключа, поскольку ключ встроен в пределах стоимости в любом случае, вы можете прибегнуть к помощи в KeyValuePair<TKey, TValue>качестве значения. Основной Смысл этого в том , что, в общем, ключ не обязательно непосредственно выводим из значения.

Тогда было бы выглядеть следующим образом:

public sealed class CustomDictionary<TKey, TValue>
  : KeyedCollection<TKey, KeyValuePair<TKey, TValue>>
{
  protected override TKey GetKeyForItem(KeyValuePair<TKey, TValue> item)
  {
    return item.Key;
  }
}

Для того, чтобы использовать эту функцию, как и в предыдущем примере, вы могли бы сделать:

CustomDictionary<string, int> custDict = new CustomDictionary<string, int>();

custDict.Add(new KeyValuePair<string, int>("key", 7));

int valueByIndex = custDict[0].Value;
int valueByKey = custDict["key"].Value;
string keyByIndex = custDict[0].Key;
Ответил 20/07/2011 в 10:21
источник пользователем

голоса
2

Вы можете также использовать SortedList и его Generic аналог. Эти два класса и в Эндрю Питерс ответа упоминается OrderedDictionary являются словарными классами , в которых элементы могут быть доступны по индексу (позиция), а также с помощью ключа. Как использовать эти классы , которые вы можете найти: SortedList Class , SortedList Generic Class .

Ответил 25/03/2015 в 18:13
источник пользователем

голоса
2

Словарь может быть не очень интуитивным для использования индекса для справки , но вы можете иметь аналогичные операции с массивом KeyValuePair :

ех. KeyValuePair<string, string>[] filters;

Ответил 06/04/2016 в 21:15
источник пользователем

голоса
1

Visual Studio в UserVoice дает ссылку на общую реализацию OrderedDictionary по dotmore.

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

class ListArray<T> : List<T[]> { }

Вы также можете объявить его с конструкторами:

class ListArray<T> : List<T[]>
{
    public ListArray() : base() { }
    public ListArray(int capacity) : base(capacity) { }
}

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

ListArray<string> settingsRead = new ListArray<string>();
using (var sr = new StreamReader(myFile))
{
    string line;
    while ((line = sr.ReadLine()) != null)
    {
        string[] keyValueStrings = line.Split(separator);
        for (int i = 0; i < keyValueStrings.Length; i++)
            keyValueStrings[i] = keyValueStrings[i].Trim();
        settingsRead.Add(keyValueStrings);
    }
}
// Later you get your key/value strings simply by index
string[] myKeyValueStrings = settingsRead[index];

Как вы, возможно, заметили, что вы можете иметь не обязательно только пар ключ / значение в вашем ListArray. В пункт массивы могут быть любой длины, как и в рваной массиве.

Ответил 03/11/2016 в 08:42
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more