Pergunta

Eu tenho um dicionário, algo como

Dictionary<Foo,String> fooDict

Eu passo através de tudo no dicionário, por exemplo.

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

Ele faz isso na ordem dos foos foram adicionadas ao dicionário, então o primeiro item adicionado é o primeiro foo retornado.

Como posso alterar a cardinalidade de modo que, por exemplo, o terceiro foo adicionado será a segunda foo voltou? Em outras palavras, eu quero mudar o seu "índice".

Foi útil?

Solução

Se você ler a documentação no MSDN você verá isto:

"A ordem na qual os itens são devolvidos é indefinido."

Você não pode gaurantee a ordem, porque um dicionário não é uma lista ou um array. É concebido para pesquisar um valor pela chave, e qualquer capacidade de valores ITERATE é apenas uma conveniência, mas a ordem não é o comportamento que você deve confiar.

Outras dicas

Você pode estar interessado no OrderedDicationary classe que vem em System.Collections.Specialized namespace.

Se você olhar para os comentários na parte inferior, alguém da MSFT publicou esta nota interessante:

Este tipo é realmente misnamed; não é uma 'pedidos' dicionário como tal, mas sim um 'indexado' dicionário. Embora, hoje não há nenhuma versão genérica equivalente deste tipo, se somarmos um no futuro é provável que vamos citar tais como tipo 'IndexedDictionary'.

Eu acho que seria trivial para derivar dessa classe e fazer uma versão genérica do OrderedDictionary.

Estou não totalmente instruídos no domínio para responder corretamente a pergunta, mas eu tenho um sentimento que o dicionário ordena os valores de acordo com a chave, a fim de executar a busca por tecla rápida. Isto sugeriria que o dicionário é classificada por valores-chave de acordo com a comparação chave. No entanto, olhando para objeto métodos, presumo que eles estão usando códigos de hash para comparar diferentes objetos, considerando não há nenhuma exigência sobre o tipo usado para chaves. Esta é apenas uma suposição. Alguém mais knowledgey deve preencher com mais detalhes.

Por que você está interessado em manipular o "índice" de um dicionário quando o seu objectivo é o de índice com tipos arbitrários?

Eu não sei se alguém vai encontrar este útil, mas aqui está o que eu acabei descobrindo. Parece-obra (pelo qual quero dizer que não lançar quaisquer excepções), mas eu ainda sou um maneiras de ser capaz de teste que funciona como espero que ele faz. Eu fiz uma coisa semelhante antes, embora.

        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);
        }
    }

A resposta curta é que não deve haver um caminho desde um dicionário "Representa uma coleção de chaves e valores." o que não implica qualquer tipo de ordenação. Qualquer corte que você pode encontrar é fora da definição da classe e pode ser passível de mudança.

Você provavelmente deve primeiro se perguntar se um dicionário é realmente chamado na presente situação, ou se você pode fugir com o uso de uma lista de KeyValuePairs.

Caso contrário, algo como isso poderia ser útil:

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;
        }

    }


}

Com o código do cliente procurando algo como isto:

    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();
    }

UPDATE: Por alguma razão ele não deixe-me comentar sobre a minha própria resposta.

De qualquer forma, IndexableDictionary é diferente de OrderedDictionary em que

  1. "Os elementos de um OrderedDictionary não são classificadas de forma alguma." Então, de foreach não pagaria a atenção para o numérica índices
  2. É fortemente digitado, para que você não tem que mexer com lançando coisas fora de DictionaryEntry estruturas
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top