我有一个类(补丁),我想排序,所以我实现了IComparer。C#排序/比较项目
但是,它需要根据用户想要怎样进行排序,例如: - KEY1,KEY2,KEY3 - KEY1,KEY3,KEY2
对于每个按键比较我已经写了的IComparer类,然而,我想知道如何实现它的连接。即排序时,我只能传递一个IComparer实例。
或者我应该为每种完全排序的IComparer类,即IComparerKey1Key2Key3,IComparerKey1Key3Key2等?
我有一个类(补丁),我想排序,所以我实现了IComparer。C#排序/比较项目
但是,它需要根据用户想要怎样进行排序,例如: - KEY1,KEY2,KEY3 - KEY1,KEY3,KEY2
对于每个按键比较我已经写了的IComparer类,然而,我想知道如何实现它的连接。即排序时,我只能传递一个IComparer实例。
或者我应该为每种完全排序的IComparer类,即IComparerKey1Key2Key3,IComparerKey1Key3Key2等?
你可以做一个通用的比较器,需要一个代表来选择关键:
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);
如果你需要几个键进行比较相结合,您可以创建使用其他comparers一个比较器:
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);
}
}
Ex充足:
var comparer = ByKeyComparer<Patch>.CompareBy(p => p.Key1)
.ThenBy(p => p.Key2)
.ThenBy(p => p.Key3);
patches.Sort(comparer);
(很明显,你可能需要添加*Descending
版本的CompareBy
和ThenBy
方法来允许按降序排序)
如果你可以使用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
。
美味的LINQ。 – FLClover 2013-03-13 10:22:16
不幸的是,如果您想对列表进行就地排序,那么这将不起作用......并且,第一个“ToList”是不必要的。 – 2013-03-13 10:22:26
在您的文本中,您已经编写了key4,但是在您的代码中已经写入了key3。 – mgttlinger 2013-03-13 10:23:04
要通过KEY1进行排序,然后按键2然后用东西等? – levi 2013-03-13 10:17:40