Вопрос

У меня есть словарь, что-то вроде

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 тем, что

  1. "Элементы OrderedDictionary никак не отсортированы". Таким образом, foreach не будет обращать внимания на числовые индексы
  2. Он строго типизирован, поэтому вам не нужно возиться с приведением объектов из структур DictionaryEntry
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top