Take the greater of two nullable values

房东的猫 提交于 2019-12-10 12:28:51

问题


Suppose I have two nullable integers:

int? a = 10;
int? b = 20;

I want to take the biggest, non-null value, such that if both values are null, the result is null.

I could write something long-winded such as:

int? max;
if (a == null)
{
    max = b;
}
else if (b == null)
{
    max = a;
}
else
{
    max = a > b ? a : b;
}

This feels a little too clunky (and possibly error-prone) for my liking. What's the simplest way to return the greater value, which also accounts for the possibility of null values?


回答1:


This works for any nullable:

Nullable.Compare(a, b) > 0 ? a : b;



回答2:


In one line using the null coalescing operator:

int? c = a > b ? a : b ?? a;



回答3:


These lines show the necessary logic with a small trick:

if (a == null) return b; // handles b== null also
if (b == null) return a;
// now a!=null, b!=null
return Math.Max(a.Value, b.Value);

or in one line using ?: (exactly the same logic)

 return a == null ? b : b == null ? a : Math.Max(a.Value, b.Value);


Edit

While the answer above is interesting for educational purposes it is not the recomended way to solve this problem. The recomended way is to not reinvent the wheel instead find the matching wheel:

As @roman pointed out there exists a Nullable.Compare() method which makes this much more readable:

return Nullable.Compare(a, b) > 0 ? a : b;



回答4:


This is a good place for the Null coalescing operator ??.
It returns the first value if the value is not null, otherwise it returns the second value.

int? c = a > b ? a : b ?? a;

Proof here

Using the fact that the comparison operator will return false if either value is null, the expression will give you the desired result:

a        | b        || a>b | a   | b??a | a>b ? a : b??a
--------------------||----------------------------------
> b      | NOT NULL ||  T  | a   | --   | a
≤ b      | NOT NULL ||  F  | --  | b    | b
NOT NULL | NULL     ||  F  | --  | a    | a
NULL     | NOT NULL ||  F  | --  | b    | b
NULL     | NULL     ||  F  | --  | NULL | NULL



回答5:


A short version is:

var result = new[] { a, b }.Max();



回答6:


How about this

 private int? Greater(int? a, int? b)
 {
   if(a.HasValue && b.HasValue)
    return a > b ? a : b;

   if(a.HasValue)
     return a;
   if(b.HasValue)
     return b;

   return null;
  }

or more concise:

 private int? Greater(int? a, int? b)
 {
   if(a.HasValue && b.HasValue)
    return a > b ? a : b;

   return a.HasValue ? a : b;
  }



回答7:


!b.HasValue || a > b ? a : b

If b is null (!b.HasValue) then a is always going to be the correct answer.

If b is not null but a is, then a > b will be false, and b will be the correct answer.

Otherwise it's the same a > b ? a : b that non-nullable integers would have.




回答8:


How about making a method capable of handling as many nullable values as you have:

public static int? GetLargestNonNull(params int?[] values)
{
    IEnumerable<int?> nonNullValues = values.Where(v => v.HasValue);

    if (nonNullValues.Any())
    {
        return nonNullValues.Select(v => v.Value).Max();
    }

    return null;
}

And use like:

int? result = GetLargestNonNull(a, b);

Except this is also capable of handling:

int? result = GetLargestNonNull(a, b, c, d, e, f);

Or you could change the method parameter to accept a List if you are working with values you've received from another source.




回答9:


I would like to add that the one-line solutions here are good. But to demystify the code a little add a brackets around the null coalescing operator

private int? Max(int? a, int? b)
{
    return a > b ? a : (b ?? a);
    //returns a if bigger else non null prefering b
}

Returns a if it is bigger, else return b ?? a - returns non null (or null if both null) prefering b




回答10:


Here is a very intuitive and readable solution. This will work for any number of values as well as any nullable struct such as say, int? or DateTime?

Also, if all values are null then it returns null.

 public static T? GetGreatestOrDefault<T>(IEnumerable<T?> values) where T : struct
    {
        var any = values.Any(a => a.HasValue);

        if (!any) return null;

        var firstOrDefault = values.Where(v => v.HasValue)
            .Select(v => v.Value)
            .OrderByDescending(o => o)
            .FirstOrDefault();

        return firstOrDefault;
    }

or you might want to do the following:

  public static T? GreatestOrDefault<T>(this IEnumerable<T?> values) where T : struct
        {
            var any = values.Any(a => a.HasValue);

            if (!any) return null;

            var firstOrDefault = values.Where(v => v.HasValue).Max();

            return firstOrDefault;
        }


来源:https://stackoverflow.com/questions/29985069/take-the-greater-of-two-nullable-values

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!