.NET中的反向排序字典

时间:2009-05-31 11:47:24

标签: c# .net dictionary iteration reverse

有没有办法可以通过c#中的SortedDictionary向后(反向)迭代?

或者有没有办法以降序开始定义SortedDictionary?

5 个答案:

答案 0 :(得分:62)

SortedDictionary本身不支持向后迭代,但您可以通过多种方式实现相同的效果。

  1. 使用.Reverse - 方法(Linq)。 (这必须预先计算整个字典输出,但这是最简单的解决方案)

    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. 使字典按降序排序。

    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. 请改用SortedList<TKey, TValue>。性能不如字典(O(n)而不是O(logn)),但你可以像数组一样对元素进行随机访问。当您使用通用IDictionary-Interface时,您不必更改代码的其余部分。

  4. 编辑::迭代SortedLists

    您只需按索引访问元素!

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

答案 1 :(得分:15)

以相反的顺序定义SortedDictionary的最简单方法是为它提供一个IComparer<TKey>,它按照与正常相反的顺序排序。

以下是来自MiscUtil的一些代码,可能会让您更轻松:

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

然后你会使用:

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

(或您使用的任何类型)。

如果您只想在一个方向上进行迭代,那么这比之后反转顺序更有效。

答案 2 :(得分:6)

如果您将数值作为键来处理创建字典时简单地否定它们,那么还有一种非常简单的方法。

答案 3 :(得分:2)

简单地在一行中创建一个反向排序的字典

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

可以使用IComparer<T>创建System.Collections.Generic.Comparer<T>。只需将IComparision<T>委托传递给其Create方法即可构建IComparer<T>

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

如果委托的重要性为(TKey, TKey) => int,则可以使用 lambda表达式 / 本地函数 / 方法来替换委托。< / p>

答案 4 :(得分:-1)

如果您使用的是.NET 3.5,则可以使用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);
        }