C# 如何在不使用OrderBy的情况下从点数组中获取具有最小X的点?

C# 如何在不使用OrderBy的情况下从点数组中获取具有最小X的点?,c#,.net,linq,linq-to-objects,C#,.net,Linq,Linq To Objects,想象一下我有 var points = new Point[] { new Point(1, 2), new Point(2, 3) }; 要获得具有最小X的点,我可以: var result = points.OrderBy(point => point.X).First(); 但对于大型阵列,我认为这不是更快的选择。有更快的选择吗?最好使用 int x = points.Min(p => p.X); var result = points.Firs

想象一下我有

 var points = new Point[]
 {
     new Point(1, 2),
     new Point(2, 3)
 };
要获得具有最小X的点,我可以:

 var result = points.OrderBy(point => point.X).First();
但对于大型阵列,我认为这不是更快的选择。有更快的选择吗?

最好使用

int x = points.Min(p => p.X);
var result = points.First(p => p.X == x);
因为这消除了对该列表进行排序的必要性(即,它是
O(n)
,而不是说
O(n log n)
)。此外,它比使用
OrderBy
First
更清晰

您甚至可以编写如下扩展方法:

static class IEnumerableExtensions {
    public static T SelectMin<T>(this IEnumerable<T> source, Func<T, int> selector) {
        if (source == null) {
            throw new ArgumentNullException("source");
        }

        int min = 0;
        T returnValue = default(T);
        bool flag = false;

        foreach (T t in source) {
            int value = selector(t);
            if (flag) {
                if (value < min) {
                    returnValue = t;
                    min = value;
                }
            }
            else {
                min = value;
                returnValue = t;
                flag = true;
            }
        }

        if (!flag) {
            throw new InvalidOperationException("source is empty");
        }

        return returnValue;
    }
静态类IEnumerableExtensions{
公共静态T SelectMin(此IEnumerable源,Func选择器){
if(source==null){
抛出新的ArgumentNullException(“源”);
}
int min=0;
T返回值=默认值(T);
布尔标志=假;
foreach(源中的T){
int值=选择器(t);
国际单项体育联合会(旗){
如果(值<最小值){
返回值=t;
最小值=数值;
}
}
否则{
最小值=数值;
返回值=t;
flag=true;
}
}
如果(!标志){
抛出新的InvalidOperationException(“源为空”);
}
返回值;
}
用法:

IEnumerable<Point> points;
Point minPoint = points.SelectMin(p => p.X);
i可数点;
Point minPoint=points.SelectMin(p=>p.X);

您可以根据自己的需要进行概括。这样做的好处是避免了在列表中重复两次。

以下方法应该是最快的,但不是最漂亮的方法:

public static T MinValue<T>(this IEnumerable<T> e, Func<T, int> f)
{
    if (e == null) throw new ArgumentException();
    var en = e.GetEnumerator();
    if (!en.MoveNext()) throw new ArgumentException();
    int min = f(en.Current);
    T minValue = en.Current;
    int possible = int.MinValue;
    while (en.MoveNext())
    {
        possible = f(en.Current);
        if (min > possible)
        {
            min = possible;
            minValue = en.Current;
        }
    }
    return minValue;
}
公共静态最小值(此IEnumerable e,Func f)
{
如果(e==null)抛出新的ArgumentException();
var en=e.GetEnumerator();
如果(!en.MoveNext())抛出新ArgumentException();
int min=f(电流);
T最小值=正常电流;
int可能=int.MinValue;
while(en.MoveNext())
{
可能=f(正常电流);
如果(最小值>可能值)
{
最小值=可能;
最小值=正常电流;
}
}
返回最小值;
}
我只包含了int扩展,但其他扩展并不重要


编辑:根据Jason修改。

NuGet提供了一个库,其中包括其他答案提供的运算符以及框架中不存在的其他一些有用操作。

除非我的逻辑失败。Min()必须检查每个元素?然后返回该值。首先,再次开始检查同一列表,直到找到具有该X值的第一个点。最坏的情况是2*n?我添加了一个扩展方法来解决此问题。第二,
2*n
O(n)
.Comment:
Count
调用是不好的,除非在
IEnumerable
上绝对必要,因为它会导致遍历列表(在一般情况下)。如果遍历
IEnumerable
是昂贵的,这是不好的。另一个注释:请注意,在
while
循环中计算
f(en.Current)
对当前元素执行两次。如果
f
的成本很高,则这不是最佳选择。