Я использую Dictionary<string, int>
, где int
- это счетчик ключей.
Теперь мне нужно получить доступ к последнему вставленному ключу внутри словаря, но я не знаю его имени. Очевидная попытка:
int LastCount = mydict[mydict.keys[mydict.keys.Count]];
не работает, потому что Dictionary.Keys
не реализует []-индексатор.
Мне просто интересно, есть ли какой-нибудь похожий класс? Я думал использовать Stack, но он хранит только строку. Теперь я могу создать свой собственный struct и затем использовать Stack<MyStruct>
, но мне интересно, есть ли другая альтернатива, по сути Dictionary, который реализует []-индексатор для ключей?
Как @Falanwe указывает в комментарии, делание чего-то вроде этого является неправильным :
int LastCount = mydict.Keys.ElementAt(mydict.Count -1);
Вы не должны зависеть от заказа ключей в Словаре. Если Вам нужен заказ, Вы должны использовать OrderedDictionary, как предложено в этом ответ. Другие ответы на этой странице интересны также.
Вы можете использовать OrderedDictionary.
Представляет коллекцию ключа/стоимости пары, которые доступны ключом или индекс.
Словарь - Хеш-таблица, таким образом, Вы понятия не имеете заказ вставки!
Если бы Вы хотите знать последний вставленный ключ, я предложил бы расширить Словарь, чтобы включать стоимость 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 ()', так, чтобы преодолеть это Вы должны будете сохранить заказанный список ключей вставленным.
Почему don' t Вы просто простираетесь, класс словаря, чтобы добавить в последнем ключе вставил собственность. Что-то как следующее, возможно?
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);
}
}
Вы всегда можете сделать это:
string[] temp = new string[mydict.count];
mydict.Keys.CopyTo(temp, 0)
int LastCount = mydict[temp[mydict.count - 1]]
Но я бы'не рекомендовал этого делать. Нет никакой гарантии, что последний вставленный ключ окажется в конце массива. Упорядочение для Keys в MSDN не определено и может быть изменено. В моем очень коротком тесте, кажется, что он упорядочивается в порядке вставки, но вам лучше встроить надлежащую систему учета, например, стек - как вы предлагаете (хотя я не вижу необходимости в struct, исходя из ваших других утверждений) - или кэш с одной переменной, если вам просто нужно знать последний ключ.
Я думаю, вы можете сделать что-то вроде этого, синтаксис может быть неправильным, давно не использовал C#. Чтобы получить последний элемент
Dictionary<string, int>.KeyCollection keys = mydict.keys;
string lastKey = keys.Last();
или использовать Max вместо Last, чтобы получить максимальное значение, я не знаю, что лучше подходит к вашему коду.
Одна альтернатива была бы KeyedCollection, если ключ включен в стоимость.
Просто создайте основное внедрение в запечатанном классе, чтобы использовать.
Таким образом заменять 'Dictionary< последовательность, int>'; (который isn' t очень хороший пример как там isn' t ясный ключ для интервала).
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];
Я соглашаюсь со второй частью Patrick' s ответ. Даже если в некоторых тестах это, кажется, держит заказ вставки, документация (и нормальное поведение для словарей и мешанин) явно указывает, что заказ неуказанный.
You' ре, просто напрашивающееся на неприятности в зависимости от заказа ключей. Добавьте свою собственную бухгалтерию (как Патрик сказал, просто единственная переменная для последнего добавленного ключа) быть уверенным. Кроме того, don' t соблазниться всеми методами такой настолько Последний и Макс на словаре, как те, вероятно, относительно ключевого компаратора (I' m не уверенный в этом).
В случае, если Вы решаете использовать опасный кодекс, который подвергается поломке, эта дополнительная функция принесет ключ от 'Dictionary< K, V>'; согласно его внутренней индексации (который для Моно и.NET в настоящее время, кажется, находится в том же заказе, как Вы добираетесь, перечисляя собственность 'Ключей').
Очень предпочтительно использовать Linq: 'dict. Ключи. 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);
}
};
Путем Вы сформулировали вопрос, принуждает меня полагать, что интервал в Словаре содержит item' s " position" на Словаре. Оценка от утверждения, что ключи - not' t сохраненный в заказе это they' ре добавило, если бы это правильно, который означал бы это ключи. Граф (или.Count - 1, если you' ре, использующее основанный на ноле), должно все еще всегда быть количество введенного в последний раз ключа?
Если that' s правильный, там любая причина Вы can' t вместо этого используют Dictionary& лейтенант; интервал, string& gt; так, чтобы Вы могли использовать mydict [mydict. Ключи. Граф]?
Я не знаю, будет ли это работать, потому что я уверен, что ключи хранятся не в порядке их добавления, но вы можете привести коллекцию KeysCollection к List
Единственное, что я могу придумать, это хранить ключи в списке поиска и добавлять ключи в список перед тем, как добавить их в словарь... но это не очень красиво.
Чтобы подробно остановиться на посту Дэниэлса и его комментариях относительно ключа, так как ключ включен в стоимости так или иначе, Вы могли обратиться к использованию 'KeyValuePair< TKey, TValue>'; как стоимость. Главное рассуждение для этого состоит в том что, в целом, Ключ isn' t обязательно непосредственно получаемый от стоимости.
Тогда it' d похожи на это:
public sealed class CustomDictionary<TKey, TValue>
: KeyedCollection<TKey, KeyValuePair<TKey, TValue>>
{
protected override TKey GetKeyForItem(KeyValuePair<TKey, TValue> item)
{
return item.Key;
}
}
Использовать это в качестве в предыдущем примере, you' d делают:
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;
Вы можете также использовать SortedList и его Универсального коллегу. Эти два класса и в ответе Эндрю Питерса упомянули, что OrderedDictionary - классы словаря, в которых к пунктам может получить доступ индекс (положение), а также ключом. Как использовать эти классы, Вы можете найти: Класс SortedList, SortedList Универсальный Класс.
Словарь может не быть очень интуитивным для использования индекса для справки, но, Вы можете перенести подобные операции со множеством KeyValuePair :
напр. 'KeyValuePair< последовательность, string> [] фильтры';
Визуальный Studio' s [UserVoice] (https://visualstudio.uservoice.com/forums/121579-visual-studio-2015/suggestions/16494583-generic-ordereddictionary) дает связь с [универсальное внедрение OrderedDictionary] (https://github.com/mattmc3/dotmore/blob/master/dotmore/Collections/Generic/OrderedDictionary.cs) dotmore.
Но если Вы только должны получить пары ключа/стоимости индексом и don' t должен получить ценности ключами, Вы можете использовать одну простую уловку. Объявите некоторый универсальный класс (я назвал его 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. Множества изделия могут иметь любую длину, как в зубчатом множестве.