Подтвердить что ты не робот

Возьмите два значения с нулевым значением

Предположим, что у меня есть два нулевых целых числа:

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

Я хочу взять самое большое, ненулевое значение, такое, что если оба значения равны нулю, результат равен нулю.

Я мог бы написать что-то длинное, например:

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

Это кажется слишком неуклюжим (и, возможно, подверженным ошибкам) ​​по моему вкусу. Какой самый простой способ вернуть большее значение, что также учитывает возможность нулевых значений?

4b9b3361

Ответ 1

Это работает для любого обнуляемого:

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

Ответ 2

В одной строке с использованием оператора нулевой коалесценции:

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

Ответ 3

Эти строки показывают необходимую логику с небольшим трюком:

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);

или в одной строке, используя ?: (точно такая же логика)

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


Edit

Хотя вышеприведенный ответ интересен для образовательных целей, не рекомендуемый способ решения этой проблемы. Рекомендуемым способом является не изобретать колесо, а найти подходящее колесо:

Как отметил @roman, существует метод Nullable.Compare(), который делает его более читаемым:

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

Ответ 4

Это хорошее место для оператора Null coalescing ??.
Он возвращает первое значение, если значение не равно null, в противном случае оно возвращает второе значение.

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

Доказательство здесь

Используя тот факт, что оператор сравнения вернет false, если любое значение null, выражение даст желаемый результат:

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

Короткий вариант:

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

Ответ 6

Как насчет этого

 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;
  }

или более кратким:

 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

Если b равно null (!b.HasValue), то a всегда будет правильным ответом.

Если b не является нулевым, но a is, то a > b будет ложным, а b будет правильным ответом.

В противном случае это то же самое a > b ? a : b, что и нецелевые целые числа.

Ответ 8

Как сделать способ, способный обрабатывать столько значений с нулевым значением, что и у вас:

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;
}

И используйте как:

int? result = GetLargestNonNull(a, b);

Кроме того, он также способен обрабатывать:

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

Или вы можете изменить параметр метода для приема списка, если вы работаете со значениями, полученными от другого источника.

Ответ 9

Я хотел бы добавить, что однолинейные решения здесь хороши. Но для demystify код немного добавит скобки вокруг оператора нулевого коалесцирования

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

Возвращает a, если он больше, else return b ?? a - возвращает не null (или null, если оба значения null) предпочитает b

Ответ 10

Вот очень интуитивное и удобочитаемое решение. Это будет работать для любого числа значений, а также для любой допускающей обнуление структуры, например, скажем, int? или DateTime?

Кроме того, если все значения равны нулю, возвращается ноль.

 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;
    }

или вы можете сделать следующее:

  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;
        }