Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用LINQ选择具有最小或最大特性值的对象_C#_.net_Linq - Fatal编程技术网

C# 如何使用LINQ选择具有最小或最大特性值的对象

C# 如何使用LINQ选择具有最小或最大特性值的对象,c#,.net,linq,C#,.net,Linq,我有一个Person对象,其DateOfBirth属性为空。是否有一种方法可以使用LINQ查询具有最早/最小DateOfBirth值的Person对象列表 我从这里开始: var firstBornDate=People.Min(p=>p.DateOfBirth.GetValueOrDefault(DateTime.MaxValue)); Null DateOfBirth值被设置为DateTime.MaxValue,以便排除最小考虑因素(假设至少有一个具有指定的DOB) 但我所做的就是将fir

我有一个Person对象,其DateOfBirth属性为空。是否有一种方法可以使用LINQ查询具有最早/最小DateOfBirth值的Person对象列表

我从这里开始:

var firstBornDate=People.Min(p=>p.DateOfBirth.GetValueOrDefault(DateTime.MaxValue));
Null DateOfBirth值被设置为DateTime.MaxValue,以便排除最小考虑因素(假设至少有一个具有指定的DOB)

但我所做的就是将firstBornDate设置为DateTime值。我想得到的是与之匹配的Person对象。我是否需要像这样编写第二个查询:

var firstBorn=People.Single(p=>(p.DateOfBirth??DateTime.MaxValue)=firstBornDate);
或者有更精简的方法吗?

再次编辑:

对不起。除了缺少空值之外,我看到的函数是错误的

按您所说的返回结果类型

我想说一个可能的解决方案是实现IComparable和use,它确实从IEnumerable返回一个元素。当然,如果您不能修改元素,这对您没有帮助。我觉得MS的设计有点奇怪

当然,如果需要,您可以始终执行for循环,或者使用Jon Skeet提供的MoreLINQ实现。

再次编辑:

People.Aggregate((curMin, x) => (curMin == null || (x.DateOfBirth ?? DateTime.MaxValue) <
    curMin.DateOfBirth ? x : curMin))
对不起。除了缺少空值之外,我看到的函数是错误的

按您所说的返回结果类型

我想说一个可能的解决方案是实现IComparable和use,它确实从IEnumerable返回一个元素。当然,如果您不能修改元素,这对您没有帮助。我觉得MS的设计有点奇怪

当然,如果需要,您可以始终执行for循环,或者使用Jon Skeet提供的MoreLINQ实现。

People.Aggregate((curMin,x)=>(curMin==null | |(x.DateOfBirth??DateTime.MaxValue)<
People.Aggregate((curMin, x) => (curMin == null || (x.DateOfBirth ?? DateTime.MaxValue) <
    curMin.DateOfBirth ? x : curMin))
curMin.DateOfBirth?x:curMin)
People.Aggregate((curMin,x)=>(curMin==null | | |)(x.DateOfBirth??DateTime.MaxValue)<
curMin.DateOfBirth?x:curMin)

不幸的是,没有内置的方法来实现这一点,但它很容易为您自己实现。以下是它的精髓:

public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source,
    Func<TSource, TKey> selector)
{
    return source.MinBy(selector, null);
}

public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source,
    Func<TSource, TKey> selector, IComparer<TKey> comparer)
{
    if (source == null) throw new ArgumentNullException("source");
    if (selector == null) throw new ArgumentNullException("selector");
    comparer ??= Comparer<TKey>.Default;

    using (var sourceIterator = source.GetEnumerator())
    {
        if (!sourceIterator.MoveNext())
        {
            throw new InvalidOperationException("Sequence contains no elements");
        }
        var min = sourceIterator.Current;
        var minKey = selector(min);
        while (sourceIterator.MoveNext())
        {
            var candidate = sourceIterator.Current;
            var candidateProjected = selector(candidate);
            if (comparer.Compare(candidateProjected, minKey) < 0)
            {
                min = candidate;
                minKey = candidateProjected;
            }
        }
        return min;
    }
}
请注意,如果序列为空,则会引发异常,如果序列中有多个元素,则会返回具有最小值的第一个元素

或者,您可以使用我们在中的实现。(当然,有一个对应的
MaxBy

通过软件包管理器控制台安装:

PM>安装软件包morelinq


不幸的是,没有一个内置的方法来实现这一点,但它很容易为您自己实现。以下是它的精髓:

public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source,
    Func<TSource, TKey> selector)
{
    return source.MinBy(selector, null);
}

public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source,
    Func<TSource, TKey> selector, IComparer<TKey> comparer)
{
    if (source == null) throw new ArgumentNullException("source");
    if (selector == null) throw new ArgumentNullException("selector");
    comparer ??= Comparer<TKey>.Default;

    using (var sourceIterator = source.GetEnumerator())
    {
        if (!sourceIterator.MoveNext())
        {
            throw new InvalidOperationException("Sequence contains no elements");
        }
        var min = sourceIterator.Current;
        var minKey = selector(min);
        while (sourceIterator.MoveNext())
        {
            var candidate = sourceIterator.Current;
            var candidateProjected = selector(candidate);
            if (comparer.Compare(candidateProjected, minKey) < 0)
            {
                min = candidate;
                minKey = candidateProjected;
            }
        }
        return min;
    }
}
请注意,如果序列为空,则会引发异常,如果序列中有多个元素,则会返回具有最小值的第一个元素

或者,您可以使用我们在中的实现。(当然,有一个对应的
MaxBy

通过软件包管理器控制台安装:

PM>安装软件包morelinq


注:为了完整性,我加入了这个答案,因为OP没有提到数据源是什么,我们不应该做任何假设

此查询给出了正确的答案,但速度可能较慢,因为它可能必须根据
人员
的数据结构对
人员
中的所有项目进行排序:

var oldest = People.OrderBy(p => p.DateOfBirth ?? DateTime.MaxValue).First();

更新:实际上我不应该称这个解决方案为“幼稚”,但是用户需要知道他在查询什么。此解决方案的“慢度”取决于底层数据。如果这是一个数组或
列表
,则LINQ to Objects别无选择,只能在选择第一项之前先对整个集合进行排序。在这种情况下,它将比建议的其他解决方案慢。但是,如果这是一个LINQ to SQL表,并且
DateOfBirth
是一个索引列,那么SQL Server将使用该索引而不是对所有行进行排序。其他自定义的
IEnumerable
实现也可以使用索引(请参阅或对象数据库),使此解决方案比需要迭代整个集合一次的
Aggregate()
MaxBy()
/
MinBy()
更快。事实上,LINQ to Objects(理论上)可以在
OrderBy()
中对排序集合(如
SortedList
)进行特殊处理,但据我所知,事实并非如此。

注意:为了完整性,我加入了这个答案,因为OP没有提到数据源是什么,我们不应该做任何假设

People.OrderBy(p => p.DateOfBirth.GetValueOrDefault(DateTime.MaxValue)).First()
此查询给出了正确的答案,但速度可能较慢,因为它可能必须根据
人员
的数据结构对
人员
中的所有项目进行排序:

var oldest = People.OrderBy(p => p.DateOfBirth ?? DateTime.MaxValue).First();
更新:实际上我不应该称这个解决方案为“幼稚”,但是用户需要知道他在查询什么。此解决方案的“慢度”取决于底层数据。如果这是一个数组或
列表
,则LINQ to Objects别无选择,只能在选择第一项之前先对整个集合进行排序。在这种情况下,它将比建议的其他解决方案慢。但是,如果这是一个LINQ to SQL表,并且
DateOfBirth
是一个索引列,那么SQL Server将使用该索引而不是对所有行进行排序。其他自定义的
IEnumerable
实现也可以使用索引(请参阅或对象数据库),使此解决方案比需要迭代整个集合一次的
Aggregate()
MaxBy()
/
MinBy()
更快。事实上,LINQ to Objects(理论上)可以在
OrderBy()
中为排序后的集合(如
SortedList
)生成特殊情况,但据我所知,它没有

People.OrderBy(p => p.DateOfBirth.GetValueOrDefault(DateTime.MaxValue)).First()
我会成功的

public class Foo {
    public int bar;
    public int stuff;
};

void Main()
{
    List<Foo> fooList = new List<Foo>(){
    new Foo(){bar=1,stuff=2},
    new Foo(){bar=3,stuff=4},
    new Foo(){bar=2,stuff=3}};

    Foo result = fooList.Aggregate((u,v) => u.bar < v.bar ? u: v);
    result.Dump();
}
会做这个把戏的

public class Foo{
public class Foo {
    public int bar;
    public int stuff;
};

void Main()
{
    List<Foo> fooList = new List<Foo>(){
    new Foo(){bar=1,stuff=2},
    new Foo(){bar=3,stuff=4},
    new Foo(){bar=2,stuff=3}};

    Foo result = fooList.Aggregate((u,v) => u.bar < v.bar ? u: v);
    result.Dump();
}
公共酒吧; 公共物品; }; void Main() { L
public static class LinqExtensions
{
    public static T MinBy<T>(this IEnumerable<T> source, Func<T, IComparable> selector)
    {
        if (source == null)
        {
            throw new ArgumentNullException(nameof(source));
        }
        if (selector == null)
        {
            throw new ArgumentNullException(nameof(selector));
        }
        return source.Aggregate((min, cur) =>
        {
            if (min == null)
            {
                return cur;
            }
            var minComparer = selector(min);
            if (minComparer == null)
            {
                return cur;
            }
            var curComparer = selector(cur);
            if (curComparer == null)
            {
                return min;
            }
            return minComparer.CompareTo(curComparer) > 0 ? cur : min;
        });
    }
}
var nullableInts = new int?[] {5, null, 1, 4, 0, 3, null, 1};
Assert.AreEqual(0, nullableInts.MinBy(i => i));//should pass
var min = data.Select(x => (key(x), x)).Min().Item2;
                            ^           ^       ^
              the sorting key           |       take the associated original item
                                Min by key(.)
var youngest = people.Select(p => (p.DateOfBirth, p)).Min().Item2;
var youngest = people.Select(p => new {age = p.DateOfBirth, ppl = p}).Min().ppl;
people.Where(p => p.DateOfBirth.HasValue)
var youngest = Enumerable.Range(0, int.MaxValue)
               .Zip(people, (idx, ppl) => (ppl.DateOfBirth, idx, ppl)).Min().Item3;
var firstBorn = People.Aggregate((min, x) => x.DateOfBirth < min.DateOfBirth ? x : min);
  public static class IEnumerableExtensions
  {
    /// <summary>
    /// Returns the element with the maximum value of a selector function.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of source.</typeparam>
    /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
    /// <param name="source">An IEnumerable collection values to determine the element with the maximum value of.</param>
    /// <param name="keySelector">A function to extract the key for each element.</param>
    /// <exception cref="System.ArgumentNullException">source or keySelector is null.</exception>
    /// <exception cref="System.InvalidOperationException">source contains no elements.</exception>
    /// <returns>The element in source with the maximum value of a selector function.</returns>
    public static TSource MaxBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) => MaxOrMinBy(source, keySelector, 1);

    /// <summary>
    /// Returns the element with the minimum value of a selector function.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of source.</typeparam>
    /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
    /// <param name="source">An IEnumerable collection values to determine the element with the minimum value of.</param>
    /// <param name="keySelector">A function to extract the key for each element.</param>
    /// <exception cref="System.ArgumentNullException">source or keySelector is null.</exception>
    /// <exception cref="System.InvalidOperationException">source contains no elements.</exception>
    /// <returns>The element in source with the minimum value of a selector function.</returns>
    public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) => MaxOrMinBy(source, keySelector, -1);


    private static TSource MaxOrMinBy<TSource, TKey>
      (IEnumerable<TSource> source, Func<TSource, TKey> keySelector, int sign)
    {
      if (source == null) throw new ArgumentNullException(nameof(source));
      if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
      Comparer<TKey> comparer = Comparer<TKey>.Default;
      TKey value = default(TKey);
      TSource result = default(TSource);

      bool hasValue = false;

      foreach (TSource element in source)
      {
        TKey x = keySelector(element);
        if (x != null)
        {
          if (!hasValue)
          {
            value = x;
            result = element;
            hasValue = true;
          }
          else if (sign * comparer.Compare(x, value) > 0)
          {
            value = x;
            result = element;
          }
        }
      }

      if ((result != null) && !hasValue)
        throw new InvalidOperationException("The source sequence is empty");

      return result;
    }
  }

public class A
{
  public int? a;
  public A(int? a) { this.a = a; }
}

var b = a.MinBy(x => x.a);
var c = a.MaxBy(x => x.a);
var firstBornDate = People.GroupBy(p => p.DateOfBirth).Min(g => g.Key).FirstOrDefault();
public struct Money : IComparable<Money>
{
   public Money(decimal value) : this() { Value = value; }
   public decimal Value { get; private set; }
   public int CompareTo(Money other) { return Value.CompareTo(other.Value); }
}
var amounts = new List<Money> { new Money(20), new Money(10) };
Money maxAmount = amounts.Max();
var amounts = new List<Money> { new Money(20), new Money(10) };
Money maxAmount = amounts.Min();
public static (double min, T obj) tMin<T>(this IEnumerable<T> ienum, 
            Func<T, double> aFunc)
        {
            var okNull = default(T);
            if (okNull != null)
                throw new ApplicationException("object passed to Min not nullable");

            (double aMin, T okObj) best = (double.MaxValue, okNull);
            foreach (T obj in ienum)
            {
                double q = aFunc(obj);
                if (q < best.aMin)
                    best = (q, obj);
            }
            return (best);
        }
(double okDist, Airport best) greatestPort = airPorts.tMin(x => x.dist(okLat, okLon));
var query = from person in People
            where person.DateOfBirth!=null
            orderby person.DateOfBirth
            select person;
var firstBorn = query.Take(1).toList();