Domanda

C'è un modo per scorrere indietro (in senso inverso) attraverso una SortedDictionary in C #?

O c'è un modo per definire il SortedDictionary al fine di cominciare decrescente?

È stato utile?

Soluzione

Il SortedDictionary sé non supportare l'iterazione indietro, ma si hanno diverse possibilità per ottenere lo stesso effetto.

  1. Usa .Reverse-Method (LINQ). (Questo dovrà pre-calcolare l'intera uscita dizionario, ma è la soluzione più semplice)

    var Rand = new Random();
    
    var Dict = new SortedDictionary<int, string>();
    
    for (int i = 1; i <= 10; ++i) {
        var newItem = Rand.Next(1, 100);
        Dict.Add(newItem, (newItem * newItem).ToString());
    }
    
    foreach (var x in Dict.Reverse()) {
        Console.WriteLine("{0} -> {1}", x.Key, x.Value);
    }
    
  2. Fare il genere dizionario in ordine decrescente.

    class DescendingComparer<T> : IComparer<T> where T : IComparable<T> {
        public int Compare(T x, T y) {
            return y.CompareTo(x);
        }
    }
    
    // ...
    
    var Dict = new SortedDictionary<int, string>(new DescendingComparer<int>());
    
  3. Usa SortedList<TKey, TValue> invece. La prestazione non è buono come il dizionario (O (n) invece di O (log n)), ma avete accesso casuale ai elementi come negli array. Quando si utilizza il generico IDictionary-Interface, non sarà necessario cambiare il resto del codice.

Modifica :: iterazione su SortedLists

Basta accedere agli elementi in base all'indice!

var Rand = new Random();


var Dict = new SortedList<int, string>();

for (int i = 1; i <= 10; ++i) {
    var newItem = Rand.Next(1, 100);
    Dict.Add(newItem, (newItem * newItem).ToString());
}

// Reverse for loop (forr + tab)
for (int i = Dict.Count - 1; i >= 0; --i) {
    Console.WriteLine("{0} -> {1}", Dict.Keys[i], Dict.Values[i]);
}

Altri suggerimenti

Il modo più semplice per definire il SortedDictionary in ordine inverso per iniziare è quello di fornire con un IComparer<TKey> che ordina in ordine inverso alla normalità.

Ecco un po 'di codice da MiscUtil che potrebbe rendere più facile per voi che:

using System.Collections.Generic;

namespace MiscUtil.Collections
{
    /// <summary>
    /// Implementation of IComparer{T} based on another one;
    /// this simply reverses the original comparison.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public sealed class ReverseComparer<T> : IComparer<T>
    {
        readonly IComparer<T> originalComparer;

        /// <summary>
        /// Returns the original comparer; this can be useful
        /// to avoid multiple reversals.
        /// </summary>
        public IComparer<T> OriginalComparer
        {
            get { return originalComparer; }
        }

        /// <summary>
        /// Creates a new reversing comparer.
        /// </summary>
        /// <param name="original">The original comparer to 
        /// use for comparisons.</param>
        public ReverseComparer(IComparer<T> original)
        {
            if (original == null)
            { 
                throw new ArgumentNullException("original");
            }
            this.originalComparer = original;
        }

        /// <summary>
        /// Returns the result of comparing the specified
        /// values using the original
        /// comparer, but reversing the order of comparison.
        /// </summary>
        public int Compare(T x, T y)
        {
            return originalComparer.Compare(y, x);
        }
    }
}

Si potrebbe quindi utilizzare:

var dict = new SortedDictionary<string, int>
     (new ReverseComparer<string>(StringComparer.InvariantCulture));

(o qualunque sia il tipo che si stava utilizzando).

Se si vuole trasferire sempre iterare in una direzione, questo sarà più efficiente di invertire l'ordine in seguito.

C'è anche un approccio molto semplice, se avete a che fare con i valori numerici come la chiave che è quello di negare semplicemente quando si crea il dizionario.

In breve creare un dizionario ordinato invertito in una riga .

var dict = new SortedDictionary<int, int>(Comparer<int>.Create((x, y) => y.CompareTo(x)));

C'è un modo per creare un IComparer<T> utilizzando System.Collections.Generic.Comparer<T>. Basta passare un delegato IComparision<T> al suo metodo Create per costruire un IComparer<T>.

var dict = new SortedDictionary<int, TValue>(
    Comparer<int>.Create(
        delegate(int x, int y)
        {
            return y.CompareTo(x);
        }
    )
);

È possibile utilizzare un espressione lambda / funzione locale / metodo per sostituire il delegato se il loro significato sono (TKey, TKey) => int.

Se si sta utilizzando .NET 3.5, è possibile utilizzare il metodo di estensione OrderByDescending:

        var dictionary = new SortedDictionary<int, string>();
        dictionary.Add(1, "One");
        dictionary.Add(3, "Three");
        dictionary.Add(2, "Two");
        dictionary.Add(4, "Four");



        var q = dictionary.OrderByDescending(kvp => kvp.Key);
        foreach (var item in q)
        {
            Console.WriteLine(item.Key + " , " + item.Value);
        }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top