我有ViewModel类,如下所示:
public class ListViewModel
{
public ObservableCollection<InfoItem> List { get; set; }
}
public interface InfoItem
{
int Reference { get; }
string Name { get; }
}
该集合按名称排序,该名称将显示在UI中。我有一个场景,其中集合包含几千个项目,我在集合中添加了一个新项目。
按名称重新排序集合的最有效方法是什么,以便新项目显示在列表中的正确位置?
答案 0 :(得分:6)
如果您的集合已经排序,则对其执行二进制搜索以找出应插入新项目的位置,然后调用Insert
。将项目添加到最后然后使用整个集合将非常浪费。
遗憾的是BinarySearch
上没有通用的IList<T>
扩展方法,但写起来应该不会太难。假设你想写一个通用的方法来做这个(我建议你这样做 - 它不会比编写InfoItem
特定的方法更难)你要么想要采用IComparer<T>
或投影,例如
public static int BinarySearch<T>(this IList<T> source, IComparer<T> comparer)
或
public static int BinarySearch<TSource, TKey>(
this IList<TSource> source,
Func<TSource, TKey> keySelector)
我建议你使返回值遵循List<T>.BinarySearch
的约定,这样如果找不到匹配,它将返回项目插入的索引的按位否定。
答案 1 :(得分:2)
由于您的收藏品已经过排序,只需Insert
您可以使用binary search找到的相应位置的新项目。不幸的是,IList<T>
上没有内置的二进制搜索,但您可以轻松地创建一个完成工作的扩展方法。实施二进制搜索时要小心,不要引入classic bug(该错误可能会导致low
和high
索引的平均值计算为low + high
溢出)。您可以使用List<T>.BinarySearch
作为模板。
答案 2 :(得分:1)
按照@JonSkeet的答案,我做了IList的BinarySearch扩展,类似于.NET sourcecode:
public static class IListBinarySearchHelper {
public static int BinarySearch<T>(this IList<T> source, int index, int count, T item, IComparer<T> comparer) {
if (index < 0) throw new Exception("Need non negative number of index.");
if (count < 0) throw new Exception("Need non negative number of count.");
if (source.Count - index < count) throw new Exception("Invalid offset length of count.");
Contract.Ensures(Contract.Result<int>() <= index + count);
Contract.EndContractBlock();
return Array.BinarySearch<T>(source.Cast<T>().ToArray(), index, count, item, comparer);
}
public static int BinarySearch<T>(this IList<T> source, T item) {
Contract.Ensures(Contract.Result<int>() <= source.Count);
return BinarySearch(source, 0, source.Count, item, null);
}
public static int BinarySearch<T>(this IList<T> source, T item, IComparer<T> comparer) {
Contract.Ensures(Contract.Result<int>() <= source.Count);
return BinarySearch(source, 0, source.Count, item, comparer);
}
}
现在我们可以做:
var nums = new ObservableCollection<int>();
nums.Add(1);
nums.Add(3);
nums.Add(8);
var result = nums.BinarySearch(1); /// return 0
result = nums.BinarySearch(4); /// return -3
这对我来说很完美。
返回值遵循与Array.BinarySearch
相同的规则,找到的索引为正数,插入点提示为负数。
按名称对我的收藏集重新排序的最有效方法是什么 新项目出现在列表中的正确位置?
要回答这个问题,只需将值插入与BinarySearch返回值相关的点即可。