最有效的方法是使用新项目</t>对ObservableCollection <t>进行排序

时间:2010-12-13 14:35:45

标签: c# wpf performance

我有ViewModel类,如下所示:

public class ListViewModel
{
    public ObservableCollection<InfoItem> List { get; set; }
}

public interface InfoItem
{
  int Reference { get; }
  string Name { get; }
}

该集合按名称排序,该名称将显示在UI中。我有一个场景,其中集合包含几千个项目,我在集合中添加了一个新项目。

按名称重新排序集合的最有效方法是什么,以便新项目显示在列表中的正确位置?

3 个答案:

答案 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(该错误可能会导致lowhigh索引的平均值计算为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返回值相关的点即可。