我有一个我想要排序的类(Patch),所以我实现了IComparer。
但是,它需要根据用户的需要进行排序,例如: - key1,key2,key3 - key1,key3,key2
对于每个密钥比较,我编写了一个IComparer类,但是,我想知道如何实现它的连接。即排序时我只能传递一个IComparer实例。
或者我应该为每种完整排序创建一个IComparer类,即IComparerKey1Key2Key3,IComparerKey1Key3Key2等?
答案 0 :(得分: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
和CompareBy
方法的ThenBy
版本,以允许按降序排序)
答案 1 :(得分:5)
如果你可以使用LINQ,那么对这样的类进行排序会很容易。
假设您有List
Patch
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
。
答案 2 :(得分:1)