Inverser Classé dans .NET Dictionnaire
-
06-09-2019 - |
Question
Est-il possible que je peux itérer en arrière (en sens inverse) par un SortedDictionary en c #?
Ou est-il un moyen de définir la SortedDictionary dans l'ordre décroissant pour commencer?
La solution
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.
-
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); }
-
Faites 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>());
-
Utilisez
SortedList<TKey, TValue>
à la place. Les performances ne sont pas aussi bon que le dictionnaire (O (n) au lieu de O (log n)), mais vous avez accès aléatoire aux éléments tels que dans des tableaux. Lorsque vous utilisez le IDictionary-Interface générique, vous ne devrez pas changer 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]);
}
Autres conseils
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.
Voici un code 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 souhaitez ensuite utiliser:
var dict = new SortedDictionary<string, int>
(new ReverseComparer<string>(StringComparer.InvariantCulture));
(ou quel que soit le type que vous utilisez).
Si vous ne voulez jamais itérer dans une direction, ce sera plus efficace que d'inverser l'ordre par la suite.
Il y a aussi une approche très simple si vous avez affaire à des valeurs numériques comme la clé qui est de les annuler simplement lorsque vous créez le dictionnaire.
créer brièvement 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>
. Il suffit de passer un délégué IComparision<T>
à 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 sont (TKey, TKey) => int
.
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);
}