在不使用IComparable <T>的情况下查找Max/Min元素

Ric*_*ver 5 .net c# list max min

说我有以下内容:

public Class BooClass
{
   public int field1;
   public double field2;
   public DateTime field3;
}

public List<BooClass> booList;
Run Code Online (Sandbox Code Playgroud)

那么例如如何使用booList.Find()在field3中获取具有最早时间的元素

编辑道歉,我打算公开所有字段以简化示例.我知道可以在linq中做到这一点,我想知道Find方法是否有简单的单行条件.

pho*_*oog 8

F#具有方便minBymaxBy运算符,我喜欢将其作为C#扩展方法实现,因为Linq库省略了它们.这有点工作,但只有一点,它可以让你避免复杂的表达,如

var earliest = booList.First(b => b.Field3 == booList.Min(e => e.Field3));
Run Code Online (Sandbox Code Playgroud)

相反,你可以输入:

var earliest = booList.MinBy(b => b.Field3);
Run Code Online (Sandbox Code Playgroud)

一个简单的实现:

static T MinBy<T, C>(this IEnumerable<T> sequence, Func<T, C> keySelector)
{
    bool first = true;
    T result = default(T);
    C minKey = default(C);
    IComparer<C> comparer = Comparer<C>.Default; //or you can pass this in as a parameter

    foreach (var item in sequence)
    {
        if (first)
        {
            result = item;
            minKey = keySelector.Invoke(item);
            first = false;
            continue;
        }

        C key = keySelector.Invoke(item);
        if (comparer.Compare(key, minKey) < 0)
        {
            result = item;
            minKey = key;
        }
    }

    return result;
}
Run Code Online (Sandbox Code Playgroud)

这也比顶部的复杂表达更有效,因为MinBy只对序列进行一次迭代,而表达式迭代不止一次且小于或等于两次.当然,排序然后取第一项需要排序,即O(n log n),而这只是O(n).

  • @SaeedAmiri但是MinBy方法在另一个类中用作库方法,简化了大量客户端代码,代价是创建一个单独的,更复杂的方法.这就是为什么我们首先有方法*.它们允许分解,减少重复/代码重用,隐藏实现细节以及其他优点.如何`var earliest = booList.MinBy(b => b.Field3);`不可读? (2认同)

Jas*_*own 5

您需要通过公共属性公开field3(我们将其称之为Field3),但您可以使用:

var earliest = booList.First(b => b.Field3 == booList.Min(e => e.Field3));
Run Code Online (Sandbox Code Playgroud)

看看Enumerable.FirstEnumerable.Min

注意:它的时间复杂度为O(n ^ 2)(二次时间),因为它通过Min每次迭代遍历列表.与Saeed Amiri的答案相比,足够大的集合将会出现严重的性能问题,该答案以O(n)(线性时间)运行.