2009-05-31 6 views
32

Y a-t-il un moyen de parcourir en arrière (inverse) un SortedDictionary dans C#?Dictionnaire inversé trié dans .NET

Ou existe-t-il un moyen de définir le TriedDictionary dans l'ordre décroissant pour commencer?

+0

Vous ne voulez pas dire Dictionnaire ... –

+0

Oui, je pense que ;-) – Dario

+3

Typo ... Merci pour tous les compilateurs humains :-) –

Répondre

59

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

  1. utilisation .Reverse -Méthode (Linq). (Cela devra pré-calculer l'ensemble de sortie de dictionnaire, mais 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. Faire le tri de 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. Utilisez SortedList<TKey, TValue> à la place. La performance n'est pas aussi bonne que celle 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'IDictionary-Interface générique, vous n'aurez pas à modifier le reste de votre code.

Modifier :: Itère sur SortedLists

Vous accédez simplement les é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]); 
} 
+0

Merci, ce fut vraiment utile! –

14

La meilleure façon de définir la SortedDictionary dans l'ordre inverse pour commencer est de lui fournir une IComparer<TKey> qui trie dans l'ordre inverse à la normale.

est Voici une partie de MiscUtil qui pourrait rendre plus facile pour vous que:

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 seriez alors utiliser:

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

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

Si vous ne voulez que parcourir dans une direction, ce sera plus efficace que d'inverser la commande par la suite.

+1

Il serait très utile de fournir une méthode de moulage intégrée au framework de Comparaison à Comparer puisque le délégué est beaucoup plus facile à manipuler (méthode lambda) ;-) – Dario

+1

J'ai aussi une classe dans MiscUtil :) –

+0

Nice ;-) Devrait faire partie du cadre de toute façon. Il y a même une telle classe en interne mais elle est privée ;-) – Dario

-1

Si vous utilisez .NET 3.5, vous pouvez utiliser la méthode d'extension 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); 
     } 
+0

C'est mauvais !! OrderByDescending a besoin de temps O (nlogn) pour trier les données qui ont déjà été triées! – Dario

+0

Bon point, je suis tellement habitué à utiliser Linq pour tout. – BFree

2

Il y a aussi une approche très simple si vous avez affaire à des valeurs numériques comme la clé qui est de nier tout simplement eux quand vous créez le dictionnaire.

0

Créez rapidement un dictionnaire trié inversé en une ligne.

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

Il y a un moyen de créer un IComparer<T> en utilisant System.Collections.Generic.Comparer<T>. Passez simplement un délégué IComparision<T> à sa méthode Create pour créer un IComparer<T>.

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

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