简体   繁体   中英

How to write C# LINQ code to select based on condition

I am looking to convert a list of one type to another type by a conversion method but only selectively (if the conversion result is null or not). It is shown in code below.

private List<B> GetBList(List<A> aList)
{
    List<B> bList = new List<B>();
    foreach (A a in aList)
    {
        B b = GetB(a);
        if (b != null)
        {
            bList.Add(b);
        }
    }
    return bList;
}

private B GetB(A a)
{
    if (a != null)
    {
        return new B();
    }
    return null;
}

Is there a way to write it using LINQ something like below. The issue with below function is that it will always move the data even if the conversion result is null. Result has to be array (array of B) and the input has to be list (list of A).

private B[] GetBList(List<A> aList)
{
    return aList.Select(GetB)?.ToArray() ?? Array.Empty<A>();
}

Please suggest. Thanks in advance!

You can select with Select(x => GetB(x)) which will return converted object. Then you should filter it with Where(x => x != null) . Then convert it to array .

Note that I have used ? after aList as aList?.Select so it will handle case when aList object is null .

private B[] GetBList(List<A> aList)
{
    return aList?.Select(x => GetB(x)).Where(x => x != null).ToArray() ?? Array.Empty<B>();
}

Edit You can use Select(GetB) instead if Select(x => GetB(x)) also.

private B[] GetBList(List<A> aList)
{
    return aList?.Select(GetB).Where(x => x != null).ToArray() ?? Array.Empty<B>();
}

I encountered many situation where I desired a function like that, hence I wrote my own extension method. In the meantime, I don't think I won anything by doing that and you do just fine with Karan's answer . On the one hand, you won't gain anything in performance and on the other hand, it only increases complexity and readability of your code.

But, it helped me a lot to get into LINQ expression, understand what's going on on behind and understand differences of IEnumerable, ICollection, etc.

For the sake of completeness and potential inspiration, I am sharing my code anyway:

public static IEnumerable<TResult> SelectByCondition<TInput, TResult>(this IEnumerable<TInput> input, Func<TInput, TResult> selector, Func<TResult, bool> checker) {
    using var enumerator = input.GetEnumerator();
    while (enumerator.MoveNext()) {
        var selection = selector(enumerator.Current);
        if (checker(selection)) {
            yield return selection;
        }
    }
}

In your case, you could use it like that:

aList?.SelectByCondition(GetB, x => x != null).ToArray() ?? Array.Empty<B>();

If you happen to encounter your scenario with the null check many times, the following simplification might still be useful:

public static IEnumerable<TResult> SelectIfNotNull<TInput, TResult>(this IEnumerable<TInput> input, Func<TInput, TResult> selector) {
    using var enumerator = input.GetEnumerator();
    while (enumerator.MoveNext()) {
        var selection = selector(enumerator.Current);
        if (selection != null) {
            yield return selection;
        }
    }
}

The actual call can then be simplified:

aList?.SelectIfNotNull(GetB).ToArray() ?? Array.Empty<B>();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM