Home > Blockchain >  In IEnumerable, how to return a specific value when no value matches the condition?
In IEnumerable, how to return a specific value when no value matches the condition?

Time:09-10

I have a method that finds all of a specific value in an IEnumerable source and returns the value and index. At this time, I want to return the default value when there is no matching value, but I don't know how.

This is because you are using yield return instead of creating and returning a new collection like List<T>.FindAll().

public static class Example
{
    public static IEnumerable<(T sought, int index)> FindAllOccurrence<T>(
        this IEnumerable<T> source, T value)
    {
        if (source == null)
            throw new ArgumentNullException(nameof(source), "The argument is null");

        if (value == null)
            throw new ArgumentNullException(nameof(value), "The argument is null");
        
        foreach (var pair in source.Select((e, i) => (e, i)))
        {
            if (pair.e.Equals(value))
            {
                yield return (pair.e, pair.i);
            }
        }

        // How do I use the if statement here?
        yield return (default(T), -1);
    }
}

When the code below is written, the statement yield return (default(T), -1); is also executed.

public static void Operation()
{
    var list = new List<int>
    {
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 3, 3, 3
    };

    var enumerable = list.FindAllOccurrence(3);

    foreach (var (value, index) in enumerable)
    {
        Console.WriteLine($"value: {value}, index: {index}");
    }
}

How do I write a proper if statement to prevent that statement from being executed?

CodePudding user response:

You want DefaultIfEmpty:

public static IEnumerable<(T sought, int index)> FindAllOccurrence<T>(
    this IEnumerable<T> source, T value)
{
    if (source == null)
        throw new ArgumentNullException(nameof(source), "The argument is null");

    if (value == null)
        throw new ArgumentNullException(nameof(value), "The argument is null");

    return source.Where(e => e.Equals(value)).Select((e, i) => (e, i)).DefaultIfEmpty((default(T), -1));
}

I'd also write this as:

public static IEnumerable<(T sought, int index)> FindAllOccurrence<T>(
    this IEnumerable<T> source, T value) =>
        source
            .Where(e => e.Equals(value))
            .Select((e, i) => (e, i))
            .DefaultIfEmpty((default(T), -1));

You get an exception already if source is null and it's not clear to me that you should get an exception if value is null.


If you want a direct answer to your question, here's how:

public static IEnumerable<(T sought, int index)> FindAllOccurrence<T>(
    this IEnumerable<T> source, T value)
{
    if (source == null)
        throw new ArgumentNullException(nameof(source), "The argument is null");

    if (value == null)
        throw new ArgumentNullException(nameof(value), "The argument is null");

    var found = false;

    foreach (var pair in source.Select((e, i) => (e, i)))
    {
        if (pair.e.Equals(value))
        {
            found = true;
            yield return (pair.e, pair.i);
        }
    }

    if (!found)
        yield return (default(T), -1);
}

CodePudding user response:

wouldn't you create the default value here? What is the default value you want? yield return ((T)Convert.ChangeType(88, typeof(T)), -1);

default value is 0, but you can change it to what you want. However it has to be of type Int

  • Related