2009-05-31 4 views
32

Gibt es eine Möglichkeit, rückwärts (in umgekehrter Reihenfolge) durch ein SortedDictionary in C# zu iterieren?Reverse Sorted Dictionary in .NET

Oder gibt es eine Möglichkeit, das SortedDictionary in absteigender Reihenfolge zu definieren?

+0

Meinst du nicht Wörterbuch ... –

+0

Ja, ich denke schon ;-) – Dario

+3

Typo ... Danke für all die menschlichen Compiler :-) –

Antwort

59

Das SortedDictionary selbst unterstützt keine Rückwärtsiteration, aber Sie haben mehrere Möglichkeiten, denselben Effekt zu erzielen.

  1. Verwenden Sie .Reverse -Methode (Linq). (Dies muss die ganze Wörterbuch Ausgabe vorab berechnen, aber die einfachste Lösung)

    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. das Wörterbuch art Marke in absteigender Reihenfolge.

    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. Verwenden SortedList<TKey, TValue> statt. Die Leistung ist nicht so gut wie die des Wörterbuchs (O (n) statt O (logn)), aber Sie haben zufälligen Zugriff auf die Elemente wie in Arrays. Wenn Sie das generische IDictionary-Interface verwenden, müssen Sie den Rest Ihres Codes nicht ändern.

bearbeiten :: Iterieren auf SortedLists

Sie greifen nur die Elemente von 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

Danke, das war wirklich hilfreich! –

14

Der einfachste Weg, um die SortedDictionary in umgekehrter Reihenfolge, mit zu beginnen zu definieren, ist es mit einem IComparer<TKey>, die normal in umgekehrter Reihenfolge sortiert zur Verfügung zu stellen.

Hier ist ein Code aus MiscUtil, die das leichter machen könnten:

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

Sie würden dann verwenden:

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

(oder wie auch immer geartete Sie verwendet).

Wenn Sie immer nur in eine Richtung iterieren möchten, ist dies effizienter als die Reihenfolge danach umzukehren.

+1

Es wäre sehr nützlich, eine Framework-integrierte Casting-Methode aus Comparison Comparer bereitzustellen, da der Delegat viel einfacher zu handhaben ist (Lambda-Methode) ;-) – Dario

+1

Ich habe auch eine Klasse in MiscUtil dafür :) –

+0

Schön ;-) Sollte sowieso ein Teil des Frameworks sein. Es gibt sogar eine solche Klasse intern aber es wird privat gehalten ;-) – Dario

-1

Wenn Sie .NET 3.5, können Sie sich die OrderByDescending Extension-Methode verwenden:

 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

Das ist schlecht !! OrderByDescending benötigt O (nlogn) Zeit, um bereits sortierte Daten zu sortieren! – Dario

+0

Guter Punkt, ich bin so daran gewöhnt, Linq für alles zu verwenden. – BFree

2

Es gibt auch einen sehr einfachen Ansatz, wenn Sie mit numerischen Werten als Schlüssel handeln, die einfach zu negieren sie beim Erstellen des Wörterbuchs.

0

Erstellen Sie kurz ein umgekehrt sortiertes Wörterbuch in einer Zeile.

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

Es gibt einen Weg, um eine IComparer<T> mit System.Collections.Generic.Comparer<T> zu erstellen. Übergeben Sie einfach einen IComparision<T> Delegaten an seine Create Methode, um eine IComparer<T> zu bauen.

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

Sie können einen Lambda-Ausdruck/lokale Funktion/Methode die Delegierten zu ersetzen, wenn ihre Bedeutung (TKey, TKey) => int ist.