web-dev-qa-db-fra.com

Dictionnaire inversé trié en .NET

Existe-t-il un moyen de répéter (en sens inverse) via un SortedDictionary en c #?

Ou existe-t-il un moyen de définir le SortedDictionary en ordre décroissant pour commencer?

37
Gal Goldman

Le SortedDictionary lui-même ne prend pas en charge l'itération vers l'arrière, mais vous avez plusieurs possibilités pour obtenir le même effet.

  1. Utilisation .Reverse- Méthode (Linq). (Cela devra pré-calculer la sortie du dictionnaire entier, mais c'est la solution la plus simple)

    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. Faites le tri du dictionnaire dans l'ordre décroissant.

    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. Utilisation SortedList<TKey, TValue> au lieu. Les performances ne sont pas aussi bonnes que celles du dictionnaire (O (n) au lieu de O (logn)), mais vous avez un accès aléatoire aux éléments comme dans les tableaux. Lorsque vous utilisez l'interface générique IDictionary, vous n'aurez pas à modifier le reste de votre code.

Edit :: Itération sur SortedLists

Vous accédez simplement aux éléments par index!

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]);
}
65
Dario

La façon la plus simple de définir le SortedDictionary dans l'ordre inverse pour commencer est de lui fournir un IComparer<TKey> qui trie dans l'ordre inverse à normal.

Voici un code de MiscUtil qui pourrait vous faciliter la tâ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);
        }
    }
}

Vous utiliseriez alors:

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

(ou quel que soit le type que vous utilisiez).

Si vous ne souhaitez que répéter dans une seule direction, cela sera plus efficace que d'inverser la commande par la suite.

16
Jon Skeet

Il existe également une approche très simple si vous avez affaire à des valeurs numériques comme clé qui consiste simplement à les annuler lorsque vous créez le dictionnaire.

6
jpope

Créez brièvement un dictionnaire trié inversé sur une seule ligne.

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

Il existe un moyen de créer un IComparer<T> en utilisant System.Collections.Generic.Comparer<T>. Passez juste un IComparision<T> déléguer à sa méthode Create pour construire un IComparer<T>.

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

Vous pouvez utiliser un expression lambda/fonction locale/méthode pour remplacer le délégué si leur signification est (TKey, TKey) => int.

3
Zheng Chen