web-dev-qa-db-ja.com

.NETの逆ソート辞書

C#でSortedDictionaryを逆方向に(逆方向に)繰り返す方法はありますか?

または、最初に降順でSortedDictionaryを定義する方法はありますか?

37
Gal Goldman

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(logn)の代わりにO(n))ほど良くはありませんが、配列のように要素にランダムにアクセスできます。汎用IDictionary-Interfaceを使用する場合、残りのコードを変更する必要はありません。

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

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

(または使用していたタイプ)。

一方向にのみ反復したい場合は、後で順序を逆にするよりも効率的です。

16
Jon Skeet

また、ディクショナリを作成するときに数値を単純に無効にするというキーとして数値を扱う場合は、非常に単純なアプローチもあります。

6
jpope

簡単に逆ソート辞書を作成します1行で

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の場合、デリゲートを置き換えることができます。

3
Zheng Chen