Изменить количество элементов в словаре C # - PullRequest
4 голосов
/ 25 сентября 2008

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

Dictionary<Foo,String> fooDict

Я перебираю все в словаре, например,

foreach (Foo foo in fooDict.Keys)
    MessageBox.show(fooDict[foo]);

Это происходит в том порядке, в котором foos были добавлены в словарь, поэтому первым добавленным элементом является первый возвращенный foo.

Как я могу изменить количество элементов, чтобы, например, третий добавленный foo был возвращен вторым foo? Другими словами, я хочу изменить его «индекс».

Ответы [ 5 ]

8 голосов
/ 25 сентября 2008

Если вы прочитаете документацию по MSDN, вы увидите это:

"Порядок, в котором возвращаются товары, не определен."

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

5 голосов
/ 25 сентября 2008

Вас может заинтересовать класс OrderedDicationary, входящий в пространство имен System.Collections.Specialized.

Если вы посмотрите на комментарии в самом низу, кто-то из MSFT разместил эту интересную заметку:

Этот тип на самом деле неправильно назван; это не «упорядоченный» словарь как таковой, а скорее «проиндексированный» словарь. Хотя сегодня не существует эквивалентной универсальной версии этого типа, если мы добавим ее в будущем, вполне вероятно, что мы назовем ее типом «IndexedDictionary».

Я думаю, что было бы тривиально извлечь из этого класса и сделать универсальную версию OrderedDictionary.

0 голосов
/ 25 сентября 2008

Короткий ответ: пути не должно быть, так как словарь «Представляет коллекцию ключей и значений». что не подразумевает какого-либо порядка. Любой взлом, который вы можете найти, находится за пределами определения класса и может измениться.

Вероятно, вам следует сначала спросить себя, действительно ли в этой ситуации требуется Словарь, или можете ли вы избежать использования списка 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's не обратил бы внимания на числовые показатели
  2. Он строго типизирован, поэтому вам не нужно возиться с приведением вещей из структур DictionaryEntry
0 голосов
/ 25 сентября 2008

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

        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);
        }
    }
0 голосов
/ 25 сентября 2008

Я не полностью образован в области , чтобы правильно ответить на вопрос, но у меня ощущение , что словарь сортирует значения по ключу, чтобы быстро выполнить поиск ключа. Это предполагает, что словарь отсортирован по ключевым значениям в соответствии со сравнением ключей. Однако, глядя на методы object , я предполагаю, что они используют хеш-коды для сравнения различных объектов, учитывая, что нет никаких требований к типу, используемому для ключей. Это всего лишь предположение. Кто-то более знающий должен заполнить более подробно.

Почему вы заинтересованы в манипулировании «индексом» словаря, когда его целью является индексирование произвольными типами?

...