How to implement the LINQ extension of the MaxOrDefault extension (x => x.SomeInt)?

When calling .Max (x => x.SomeInt) in IEnumerable, you are usually happy to return "0" if the enumerated one contains no elements. However, the implementation of LINQ.Max (x => x.SomeInt) fails because the sequence contains no elements.

Therefore, the function .MaxOrDefault (x => x.SomeInt) would be useful.

We should not just call .Any () then.Max (func), because this causes a valid "possible multiple enumeration" in Resharper.

I did one of the following:

    public static TResult MaxOrDefault<T, TResult>(this IEnumerable<T> enumerable, Func<T, TResult> func)
    {
        var list = enumerable.ToList();
        if (!list.Any()) return default(TResult);

        return list.Max(func);
    }

However, this has the disadvantage of first listing a list that is suboptimal and should not be unnecessary.

Is there a better way?

+4
4

, :

public static TResult MaxOrDefault<T, TResult>(this IEnumerable<T> enumerable, Func<T, TResult> func)
{
    return enumerable.Select(func).DefaultIfEmpty().Max();
}

DefaultIfEmpty , , IEnumerable, , default(TResult), .. 0 .

+8

DefaultIfEmpty(), ( ), .

var enumeration = ...;

var max = enumeration.DefaultIfEmpty().Max(x => ...);
+1

microsoft Max, , , , , , , .

    public static TSource MaxOrDefault<TSource>(this IEnumerable<TSource> source) {
        if (source == null) throw Error.ArgumentNull("source");
        Comparer<TSource> comparer = Comparer<TSource>.Default;
        TSource value = default(TSource);
        if (value == null) {
            foreach (TSource x in source) {
                if (x != null && (value == null || comparer.Compare(x, value) > 0))
                    value = x;
            }
            return value;
        }
        else {
            bool hasValue = false;
            foreach (TSource x in source) {
                if (hasValue) {
                    if (comparer.Compare(x, value) > 0)
                        value = x;
                }
                else {
                    value = x;
                    hasValue = true;
                }
            }

            return value;
        }
    }

, .

    public static TResult MaxOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector) {
        return MaxOrDefault(Enumerable.Select(source, selector));
    }

,

if (hasValue) return value;
throw Error.NoElements();

return value;
+1

, MoveNext() false , , , :

public static TResult MaxOrDefault<T, TResult>(this IEnumerable<T> source, Func<T, TResult> func) where TResult : IComparable
{
  if(source == null)
    throw new ArgumentNullException("source");
  using(var en = source.GetEnumerator())
    if(en.MoveNext())
    {
      TResult max = func(en.Current);
      while(en.MoveNext())
      {
        TResult cur = func(en.Current);
        if(max == null || (cur != null && cur.CompareTo(max) > 0))
          max = cur;
      }
      return max;
    }
  else
    return default(TResult);
}

, , IEnumerable ( IQueryable, ). , Linq, IQueryable , IQueryable:

public static TResult MaxOrDefault<T, TResult>(this IQueryable<T> source, Func<T, TResult> func) where TResult : IComparable
{
  if(source == null)
    throw new ArgumentNullException("source");
  return source.OrderByDescending(func).Select(func).FirstOrDefault();
}

Linq, , SQL.

But it is less efficient than our earlier version for enumerations in memory, but provided that both options usually allow normal overloads to be better chosen.

0
source

Source: https://habr.com/ru/post/1569491/


All Articles