表达式树而不是使用LINQ

时间:2011-10-02 20:07:24

标签: c#

我有LIST<T> where T:IComparable<T>

我想写一个List<T> GetFirstNElements (IList<T> list, int n) where T :IComparable <T>,它使用表达式树返回前n个不同的最大元素(列表可以有dupes)。

3 个答案:

答案 0 :(得分:3)

在我最近写的一些性能关键代码中,我有一个非常相似的要求 - 候选集非常大,而且需要的数量非常小。为了避免对整个候选集进行排序,我使用了一个自定义扩展方法,该方法只保留链接列表中到目前为止找到的n个最大项。然后我可以简单地说:

  • 循环一次候选人
  • 如果我还没有找到“n”项,或者当前项更好而不是已经选择的最差项,那么在链表中添加它(在正确的位置)(插入)在这里便宜)
    • 如果我们现在选择了超过“n”,则删除最差(删除很便宜)
然后我们完成了;在此结束时,链表包含已排序的最佳“n”项。不需要使用表达式树,也不需要“排序巨大的列表”开销。 之类的东西

public static IEnumerable<T> TakeTopDistinct<T>(this IEnumerable<T> source, int count)
{
    if (source == null) throw new ArgumentNullException("source");
    if (count < 0) throw new ArgumentOutOfRangeException("count");
    if (count == 0) yield break;

    var comparer = Comparer<T>.Default;
    LinkedList<T> selected = new LinkedList<T>();

    foreach(var value in source)
    {
        if(selected.Count < count // need to fill
            || comparer.Compare(selected.Last.Value, value) < 0 // better candidate
            )
        {
            var tmp = selected.First;
            bool add = true;
            while (tmp != null)
            {
                var delta = comparer.Compare(tmp.Value, value);
                if (delta == 0)
                {
                    add = false; // not distinct
                    break;
                }
                else if (delta < 0)
                {
                    selected.AddBefore(tmp, value);
                    add = false;
                    if(selected.Count > count) selected.RemoveLast();
                    break;
                }
                tmp = tmp.Next;
            }
            if (add && selected.Count < count) selected.AddLast(value);
        }
    }
    foreach (var value in selected) yield return value;
}

答案 1 :(得分:0)

如果我的问题正确,您只想对列表中的条目进行排序 您是否可以实现IComparable并使用列表的“排序”方法?
“IComparable”中的代码可以处理树比较以及您想要用来比较和排序的所有内容,这样您就可以使用Sort mechnism。

List<T> GetFirstNElements (IList<T> list, int n) where T :IComparable <T>{
    list.Sort();
    List<T> returnList = new List<T>();
    for(int i = 0; i<n; i++){
        returnList.Add(list[i]);
    }
    return returnList;
}

不是最快的代码; - )

答案 2 :(得分:0)

这样做的标准算法,在预期时间O(list.Length)在维基百科中作为“quickfindFirstK”在此页面上:

http://en.wikipedia.org/wiki/Selection_algorithm#Selecting_k_smallest_or_largest_elements

这改善了@Marc Gravell的答案,因为无论n的值如何,它的预期运行时间在输入列表的长度上是线性的。