Измените мощность элемента в словаре C #
-
02-07-2019 - |
Вопрос
У меня есть словарь, что-то вроде
Dictionary<Foo,String> fooDict
Я просматриваю все, что есть в словаре, например
foreach (Foo foo in fooDict.Keys)
MessageBox.show(fooDict[foo]);
Он делает это в том порядке, в каком foo были добавлены в словарь, поэтому первый добавленный элемент - это первый возвращенный foo.
Как я могу изменить мощность так, чтобы, например, третий добавленный foo был вторым возвращенным foo?Другими словами, я хочу изменить его "индекс".
Решение
Если вы прочтете документацию по MSDN, вы увидите это:
"Порядок, в котором возвращаются товары, не определен".
Вы не можете гарантировать порядок, потому что словарь - это не список и не массив.Он предназначен для поиска значения по ключу, и любая возможность повторять значения - это просто удобство, но порядок - это не поведение, от которого вы должны зависеть.
Другие советы
Возможно, вас заинтересует OrderedDicationary
класс, который входит в System.Collections.Specialized
пространство имен.
Если вы посмотрите на комментарии в самом низу, кто-то из MSFT опубликовал эту интересную заметку:
Этот тип на самом деле неправильно назван;это не "упорядоченный" словарь как таковой, а скорее "индексированный" словарь.Хотя на сегодняшний день не существует эквивалентной универсальной версии этого типа, если мы добавим ее в будущем, вполне вероятно, что мы назовем такой тип 'IndexedDictionary'.
Я думаю, было бы тривиально получить производное от этого класса и создать универсальную версию OrderedDictionary.
Я такой и есть не до конца образован в данной области чтобы правильно ответить на вопрос, но у меня есть чувство что словарь сортирует значения в соответствии с ключом, чтобы выполнить быстрый поиск по ключу.Это предполагает, что словарь отсортирован по ключевым значениям в соответствии со сравнением ключей.Однако, глядя на объект методы, я предполагаю, что они используют хэш-коды для сравнения различных объектов, учитывая, что нет требований к типу, используемому для ключей.Это всего лишь предположение.Кто-то более осведомленный должен рассказать более подробно.
Почему вы заинтересованы в манипулировании "индексом" словаря, когда его целью является индексирование произвольными типами?
Я не знаю, найдет ли кто-нибудь это полезным, но вот что я в итоге выяснил.Кажется, это работает (под этим я подразумеваю, что оно не создает никаких исключений), но я все еще далек от возможности проверить, работает ли это так, как я надеюсь.Однако я уже делал нечто подобное раньше.
public void sortSections()
{
//OMG THIS IS UGLY!!!
KeyValuePair<ListViewItem, TextSection>[] sortable = textSecs.ToArray();
IOrderedEnumerable<KeyValuePair<ListViewItem, TextSection>> sorted = sortable.OrderBy(kvp => kvp.Value.cardinality);
foreach (KeyValuePair<ListViewItem, TextSection> kvp in sorted)
{
TextSection sec = kvp.Value;
ListViewItem key = kvp.Key;
textSecs.Remove(key);
textSecs.Add(key, sec);
}
}
Короткий ответ заключается в том, что не должно быть способа, поскольку словарь "Представляет собой набор ключей и значений". что не подразумевает какого-либо упорядочения.Любой взлом, который вы можете обнаружить, выходит за рамки определения класса и может быть подвержен изменениям.
Вероятно, вам следует сначала спросить себя, действительно ли в этой ситуации требуется словарь, или вам может сойти с рук использование списка пар KeyValuePairs.
В противном случае, что-то вроде этого могло бы быть полезно:
public class IndexableDictionary<T1, T2> : Dictionary<T1, T2>
{
private SortedDictionary<int, T1> _sortedKeys;
public IndexableDictionary()
{
_sortedKeys = new SortedDictionary<int, T1>();
}
public new void Add(T1 key, T2 value)
{
_sortedKeys.Add(_sortedKeys.Count + 1, key);
base.Add(key, value);
}
private IEnumerable<KeyValuePair<T1, T2>> Enumerable()
{
foreach (T1 key in _sortedKeys.Values)
{
yield return new KeyValuePair<T1, T2>(key, this[key]);
}
}
public new IEnumerator<KeyValuePair<T1, T2>> GetEnumerator()
{
return Enumerable().GetEnumerator();
}
public KeyValuePair<T1, T2> this[int index]
{
get
{
return new KeyValuePair<T1, T2> (_sortedKeys[index], base[_sortedKeys[index]]);
}
set
{
_sortedKeys[index] = value.Key;
base[value.Key] = value.Value;
}
}
}
С клиентским кодом, выглядящим примерно так:
static void Main(string[] args)
{
IndexableDictionary<string, string> fooDict = new IndexableDictionary<string, string>();
fooDict.Add("One", "One");
fooDict.Add("Two", "Two");
fooDict.Add("Three", "Three");
// Print One, Two, Three
foreach (KeyValuePair<string, string> kvp in fooDict)
Console.WriteLine(kvp.Value);
KeyValuePair<string, string> temp = fooDict[1];
fooDict[1] = fooDict[2];
fooDict[2] = temp;
// Print Two, One, Three
foreach (KeyValuePair<string, string> kvp in fooDict)
Console.WriteLine(kvp.Value);
Console.ReadLine();
}
Обновить: По какой-то причине это не позволяет мне прокомментировать мой собственный ответ.
В любом случае, IndexableDictionary отличается от OrderedDictionary тем, что
- "Элементы OrderedDictionary никак не отсортированы". Таким образом, foreach не будет обращать внимания на числовые индексы
- Он строго типизирован, поэтому вам не нужно возиться с приведением объектов из структур DictionaryEntry