Возвращение значения по умолчанию из списка <>, если совпадение не найдено - PullRequest
1 голос
/ 04 июня 2019

Я пытаюсь найти более чистый способ возврата значения по умолчанию, когда не найдено совпадений.Пример, который я написал, чтобы лучше всего продемонстрировать мой вопрос, показан ниже из LinqPad

Таким образом, в общем случае, если заданное значение Age не найдено в списке, SingleOrDefault возвращает значение null как обычно.Поэтому вместо того, чтобы возвращать null, я выбираю самое высокое Threshold из независимо от значения Age.

Однако вместо использования if или использования ?? (null coalescing operator) есть ли более чистый способ достижения этого?Возможно, установить значение по умолчанию в свойствах get и set of Age внутри класса test?

void Main()
{
    var list = new List<test>()
    { 
        new test ( 55, 27 ),
        new test ( 56, 28),
        new test ( 57, 29),
        new test ( 59, 30),
        new test ( 60, 31) //60+
    };

    var res = list.SingleOrDefault(x => x.Age == 61);   

    if (res == null)
    {
        list.Max(l => l.Threshold).Dump();
    }
    else
    {
        res.Threshold.Dump();   
    }  
} 

class test
{
    public int Age 
    { 
        get;
        set;
    }   

    public int Threshold 
    {   
        get;
        set;
    }

    public test(int age, int threshold)
    {
        Age = age;
        Threshold = threshold;
    }
}

Ответы [ 3 ]

5 голосов
/ 04 июня 2019

Вы можете использовать DefaultIfEmpty() из LINQ:

var res = list.Where(x => x.Age == 61)
              .Select(t => t)
              .DefaultIfEmpty(list.First(x => x.Threshold == list.Max(t => t.Threshold)))
              .SingleOrDefault();
1 голос
/ 05 июня 2019

Полагаю, вы хотели бы иметь метод LINQ SingleOrMax, который вы можете использовать следующим образом:

var res = list.SingleOrMax(x => x.Age == 61, x => x.Threshold);

Первое выражение является предикатом для SingleOrDefault, а второе выражение выбираетключ, который будет использоваться для поиска элемента max, если это необходимо.

Вот оно:

public static TSource SingleOrMax<TSource, TMaxKey>(this IEnumerable<TSource> source,
    Func<TSource, bool> predicate, Func<TSource, TMaxKey> maxKeySelector)
{
    var result = source.SingleOrDefault(predicate);
    if (result != default) return result;
    var maxKeyComparer = Comparer<TMaxKey>.Default;
    TSource max = default;
    TMaxKey maxKey = default;
    int count = 0;
    foreach (var item in source)
    {
        var key = maxKeySelector(item);
        if (count == 0 || maxKeyComparer.Compare(key, maxKey) > 0)
        {
            max = item;
            maxKey = key;
        }
        count++;
    }
    // If you remove the line bellow, then rename this method to SingleOrMaxOrDefault
    if (count == 0) throw new InvalidOperationException("Sequence contains no elements");
    return max;
}
0 голосов
/ 04 июня 2019

Вы всегда можете использовать метод расширения, хотя это кажется немного излишним.

public static Test SingleAgeOrMaxThreshold(this IEnumerable<Test> items, int age)
{
    Test max = null;
    foreach (Test t in items)
    {
        if (t.Age == age)
            return t;

        if (max == null || t.Threshold > max.Threshold)
            max = t;
    }

    return max;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...