Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to append objects to an Enumerable in a foreach loop

I'm doing a C# exercise to create an operation that takes a collection, performs a function on each object in the collection, and returns a collection of modified objects.

My code is currently as follows:

public static IEnumerable<U> Accumulate<T, U>(this IEnumerable<T> collection, Func<T, U> func)
{
    IEnumerable<U> output = Enumerable.Empty<U>();

    foreach (T item in collection)
    {
        output.Append(func(item));
    }

    return output;
}

This is only returning an empty collection, and I have no idea why.

I have tried creating a copy of the item in the foreach after seeing this approach in another thread, like so:

foreach (T item in collection)
    {
        U copy = func(item);
        output.Append(copy);
    }

but that didn't solve anything.

I did some research but couldn't really find any examples doing exactly what I'm trying to do here. I read some things about closure, but couldn't really understand it, as I'm new to C#.

like image 280
Callum Lackie Avatar asked Dec 14 '22 15:12

Callum Lackie


2 Answers

To answer your actual question: The reason it isn't working is because

output.Append(func(item));

doesn't change output - instead, it returns a new sequence which is func(item) appended to output. Thus when you eventually return output you are just returning the original, empty sequence.

You could make yours work by this simple change:

output = output.Append(func(item));

However, this is not an efficient approach - you're much better off using yield, by modifying your method as follows:

public static IEnumerable<U> Accumulate<T, U>(this IEnumerable<T> collection, Func<T, U> func)
{
    foreach (T item in collection)
    {
        yield return func(item);
    }
}

Although note that that is more simply expressed as:

public static IEnumerable<U> Accumulate<T, U>(this IEnumerable<T> collection, Func<T, U> func)
{
    return collection.Select(item => func(item));
}

But it is useful to know about how to do this with yield so that you can write solutions to more complex Linq-like problems.

like image 62
Matthew Watson Avatar answered Dec 22 '22 00:12

Matthew Watson


Usually, when I want to achieve this kind of behaviour, I make use of C# Iterators. They are so usefull when you want to process an iteration on some kind of data and, at each iteration, return a value that is appended to your resulting collection.

Take a look at the docs: MS Docs

like image 43
mororo Avatar answered Dec 21 '22 22:12

mororo