【问题标题】:C# Sorting/comparing itemsC# 排序/比较项目
【发布时间】:2013-03-13 18:52:00
【问题描述】:

我有一个想要排序的类(补丁),所以我实现了 IComparer。

但是,它需要根据用户的需要进行排序,例如: - 键 1、键 2、键 3 - key1, key3, key2

对于每个键比较,我编写了一个 IComparer 类,但是,我想知道如何实现它的连接。即排序时我只能传递一个 IComparer 实例。

或者我应该为每种完整排序创建一个 IComparer 类,即 IComparerKey1Key2Key3、IComparerKey1Key3Key2 等?

【问题讨论】:

  • 您想先按 key1 排序,然后按 key2 再按某事等等?

标签: c# wpf sorting icomparer


【解决方案1】:

您可以创建一个通用比较器,它需要委托来选择键:

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 方法以允许按降序排序)

【讨论】:

    【解决方案2】:

    如果您可以使用 LINQ,那么像这样对类进行排序将非常容易。 假设您有一个 ListPatch List&lt;Patch&gt;,并且您想按 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

    【讨论】:

    • 不幸的是,如果您想对列表进行就地排序,这将不起作用......而且,第一个“ToList”是不必要的。
    • 在你的文本中你写了key4但是在你的代码中你写了key3。
    • 我希望我可以将 LINQ 方法与其他解决方案中的比较器一起使用。比较是微不足道的。
    【解决方案3】:

    您也可以使用LINQ Dynamic Query Library 或者看看Dynamic LINQ OrderBy

    【讨论】:

      猜你喜欢
      • 2016-10-17
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多