我需要一个带有两个参数的扩展方法:目标IList<T>
和自定义比较器。
public static void CustomSort<T>( IList<T> target, IComparer<T> comparer )
{
...
}
扩展方法的工作是按照自定义比较器指示的顺序排列目标元素。
以下是无法工作的一些解决方案:
List<T>.Sort
进行就地排序,这基本上就是我所追求的。但我不能假设目标的具体类型是List<T>
。相反,我需要调用目标的Remove
和Insert
方法,以使其元素按正确顺序排列。目标列表可能是可观察的,因此重要的是解决方案不会进行比获得所需订单所需的更多删除和插入。
答案 0 :(得分:2)
我觉得这样的事情对你有用。
我们对一组偏移进行排序,然后确定需要应用的增量集,最后应用它们来生成新排序的IList。
public static void CustomSort<T>( IList<T> list , IComparer<T> comparer )
{
int[] unsorted = Enumerable.Range(0,list.Count).ToArray() ;
int[] sorted = Enumerable.Range(0,list.Count).OrderBy( x => list[x] , comparer ).ToArray() ;
var moves = sorted.Zip( unsorted , (x,y) => new{ Src = x , Dest = y , } ).Where( x => x.Src != x.Dest ).OrderBy( x => x.Src ).ToArray() ;
// at this point, moves is a list of moves, from a source position to destination position.
// We enumerate over this and apply the moves in order.
// To do this we need a scratch pad to save incomplete moves, where an existing item has
// been over-written, but it has not yet been moved into its final destination.
Dictionary<int,T> scratchPad = new Dictionary<int, T>() ; // a parking lot for incomplete moves
foreach ( var move in moves )
{
T value ;
// see if the source value is on the scratchpad.
// if it is, use it and remove it from the scratch pad.
// otherwise, get it from the indicated slot in the list.
if ( scratchPad.TryGetValue( move.Src , out value ) )
{
scratchPad.Remove( move.Src );
}
else
{
value = list[ move.Src ] ;
}
// if the destination is after the source position, we need to put
// it on the scratch pad, since we haven't yet used it as a source.
if ( move.Dest > move.Src )
{
scratchPad.Add( move.Dest , list[ move.Dest ]);
}
// finally, move the source value into its destination slot.
list[ move.Dest ] = value ;
}
return ;
}
答案 1 :(得分:1)
评论表明,如上所述,这实际上可能是一个难题。那么如果我们从不同的角度来看待这个问题呢:
ObservableRangeCollection<T>
之类的内容,以便在可观察的集合中获得AddRange
。如果可能,一些简单的代码可以确定集合是List<T>
还是ObservableRangeCollection<T>
以使用AddRange
。E.g。
public static void SmartSort<T>(IList<T> source)
{
var sortedList = source.OrderBy(x => x).ToList();
if (source.SequenceEqual(sortedList))
return;
var list = source as List<T>;
var collection = source as ObservableRangeCollection<T>;
if (list != null)
{
list.Clear();
list.AddRange(sortedList);
}
else if (collection != null)
collection.ReplaceRange(sortedList);
else
{
for (int i = 0; i < source.Count; i++)
source[i] = sortedList[i];
}
}
答案 2 :(得分:1)
使用LINQ扩展方法排序并获取一个新的List,最后隐式调用ToList()
;
然后告诉您的可观察列表暂停(不关心更改)
清除您的可观察列表
从linq-ordered列表中将项添加到observable列表中。
告诉您的可观察列表继续观看更改
观察者观察的变化数量是否有效;从算法效率的角度来看,我试试这个解决方案。您可能永远不需要进一步优化。请记住: premature optimization is the root of all evil