Pregunta

Tengo un diccionario, algo así como

Dictionary<Foo,String> fooDict

Paso a través de todo en el diccionario, por ejemplo

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

Lo hace en el orden en que los foos se agregaron al diccionario, por lo que el primer elemento agregado es el primer foo devuelto.

¿Cómo puedo cambiar la cardinalidad para que, por ejemplo, el tercer foo agregado sea el segundo foo devuelto? En otras palabras, quiero cambiar su " índice "

¿Fue útil?

Solución

Si lee la documentación en MSDN verá esto:

" El orden en que se devuelven los artículos no está definido. "

No puede garantizar el orden, porque un Diccionario no es una lista o una matriz. Está destinado a buscar un valor por la clave, y cualquier capacidad de iterar valores es solo una conveniencia, pero el orden no es un comportamiento del que debe depender.

Otros consejos

Puede interesarle el OrderedDicationary clase que viene en < code> System.Collections.Specialized namespace.

Si observa los comentarios en la parte inferior, alguien de MSFT ha publicado esta interesante nota:

  

Este tipo está mal nombrado; no es un diccionario "ordenado" como tal, sino un diccionario "indexado". Aunque hoy no existe una versión genérica equivalente de este tipo, si agregamos una en el futuro, es probable que la nombremos como tipo 'IndexedDictionary'.

Creo que sería trivial derivar de esta clase y hacer una versión genérica de OrderedDictionary.

No estoy completamente educado en el dominio para responder correctamente la pregunta, pero tengo la sensación de que el diccionario clasifica los valores de acuerdo con la clave, para realiza una búsqueda rápida de teclas. Esto sugeriría que el diccionario está ordenado por valores clave según la comparación de claves. Sin embargo, al observar los métodos de objeto , supongo que están utilizando códigos hash para comparar diferentes objetos, considerando que no hay ningún requisito sobre el tipo utilizado para las claves. Esto es solo una suposición. Alguien más conocedor debe completar con más detalle.

¿Por qué está interesado en manipular el " índice " de un diccionario cuando su propósito es indexar con tipos arbitrarios?

No sé si alguien encontrará esto útil, pero esto es lo que terminé descubriendo. Parece que funciona (con lo que quiero decir que no arroja ninguna excepción), pero todavía estoy muy lejos de poder probar que funciona como espero que lo haga. Sin embargo, he hecho algo similar antes.

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

La respuesta corta es que no debería haber una forma ya que un Diccionario "representa una colección de claves y valores". lo que no implica ningún tipo de pedido. Cualquier pirateo que pueda encontrar está fuera de la definición de la clase y puede estar sujeto a cambios.

Probablemente primero debería preguntarse si realmente se necesita un Diccionario en esta situación, o si puede salirse con la suya usando una Lista de KeyValuePairs.

De lo contrario, algo como esto podría 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;
        }

    }


}

Con un código de cliente similar a este:

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

ACTUALIZACIÓN: por alguna razón no me deja comentar sobre mi propia respuesta.

De todos modos, IndexableDictionary es diferente de OrderedDictionary en eso

  1. " Los elementos de un OrderedDictionary no están ordenados de ninguna manera. " Entonces foreach no prestará atención a los índices numéricos
  2. Está fuertemente tipado, por lo que no tiene que perder el tiempo lanzando cosas fuera de las estructuras DictionaryEntry
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top