3

ソートしたいクラス(Patch)があるので、IComparerを実装しました。

ただし、ユーザーの希望に応じて並べ替える必要があります。例:-key1、key2、key3-key1、key3、key2

キー比較ごとにIComparerクラスを作成しましたが、その接続を実装する方法を考えていました。つまり、並べ替えるときに渡すことができるIComparerインスタンスは1つだけです。

または、IComparerKey1Key2Key3、IComparerKey1Key3Key2などの完全な並べ替えの種類ごとにIComparerクラスを作成する必要がありますか?

4

3 に答える 3

6

デリゲートを使用してキーを選択する汎用比較器を作成できます。

class ByKeyComparer<T, TKey> : IComparer<T>
{
    private readonly Func<T, TKey> _keySelector;
    private readonly IComparer<TKey> _keyComparer;

    public ByKeyComparer(Func<T, TKey> keySelector, IComparer<TKey> keyComparer = null)
    {
        if (keySelector == null) throw new ArgumentNullException("keySelector");
        _keySelector = keySelector;
        _keyComparer = keyComparer ?? Comparer<TKey>.Default;
    }

    public int Compare(T x, T y)
    {
        return _keyComparer.Compare(_keySelector(x), _keySelector(y));
    }
}

型推論を利用するためのヘルパークラスを使用する(したがって、キーの型を指定する必要はありません)。

static class ByKeyComparer<T>
{
    public static IComparer<T> Create<TKey>(Func<T, TKey> keySelector, IComparer<TKey> keyComparer = null)
    {
        return new ByKeyComparer<T, TKey>(keySelector, keyComparer);
    }
}

次のように使用できます。

var patchVersionComparer = ByKeyComparer<Patch>.Create(p => p.Version);
patches.Sort(patchVersionComparer);

複数の比較キーを組み合わせる必要がある場合は、他の比較プログラムを使用する比較プログラムを作成できます。

class CompositeComparer<T> : IComparer<T>
{
    private readonly IEnumerable<IComparer<T>> _comparers;

    public CompositeComparer(IEnumerable<IComparer<T>> comparers)
    {
        if (comparers == null) throw new ArgumentNullException("comparers");
        _comparers = comparers;
    }

    public CompositeComparer(params IComparer<T>[] comparers)
        : this((IEnumerable<IComparer<T>>)comparers)
    {
    }

    public int Compare(T x, T y)
    {
        foreach (var comparer in _comparers)
        {
            int result = comparer.Compare(x, y);
            if (result != 0)
                return result;
        }
        return 0;
    }
}

使用例:

var comparer = new CompositeComparer<Patch>(
                       ByKeyComparer<Patch>.Create(p => p.Key1),
                       ByKeyComparer<Patch>.Create(p => p.Key2),
                       ByKeyComparer<Patch>.Create(p => p.Key3));
patches.Sort(comparer);

編集:これがより流暢なAPIです:

static class ByKeyComparer<T>
{
    public static IComparer<T> CompareBy<TKey>(Func<T, TKey> keySelector, IComparer<TKey> keyComparer = null)
    {
        return new ByKeyComparer<T, TKey>(keySelector, keyComparer);
    }
}

static class ComparerExtensions
{
    public static IComparer<T> ThenBy<T, TKey>(this IComparer<T> comparer, Func<T, TKey> keySelector, IComparer<TKey> keyComparer = null)
    {
        var newComparer = ByKeyComparer<T>.CompareBy(keySelector, keyComparer);

        var composite = comparer as CompositeComparer<T>;
        if (composite != null)
            return new CompositeComparer<T>(composite.Comparers.Concat(new[] { newComparer }));
        return new CompositeComparer<T>(comparer, newComparer);
    }
}

例:

var comparer = ByKeyComparer<Patch>.CompareBy(p => p.Key1)
                                   .ThenBy(p => p.Key2)
                                   .ThenBy(p => p.Key3);
patches.Sort(comparer);

(明らかに、降順での順序付けを可能にするために、およびメソッド*Descendingのバージョンを追加することをお勧めします)CompareByThenBy

于 2013-03-13T10:37:27.503 に答える
5

LINQを使用できる場合は、このようなクラスを並べ替えるのは非常に簡単です。を持っていてListPatch List<Patch>key2、key1、key4で並べ替えたいとします。あなたがすることは:

List<Patch> patches = new List<Patch>();
patches = GetPatches().ToList().OrderBy(p=>p.Key2).ThenBy(p=>p.Key1).ThenBy(p=>p.Key4).ToList();

それで全部です。linqが大好きです。:)

ToList関数がリスト自体を返す場合、最初は必要ありません。

于 2013-03-13T10:20:54.677 に答える
1

LINQ動的クエリライブラリを使用する か、動的LINQOrderByを確認することもできます

于 2013-03-13T10:25:56.180 に答える