toddmo toddmo -4 years ago 85
C# Question

Creating a collection with a function to obtain the next member

I need to accumulate values into a collection, based on an arbitrary function. Each value is derived from calling a function on the previous value.

My current attempt:

public static T[] Aggregate<T>(this T source, Func<T, T> func)
{
var arr = new List<T> { };
var current = source;
while(current != null)
{
arr.Add(current);
current = func(current);
};
return arr.ToArray();
}


Is there a built-in .Net Framework function to do this?

Answer Source

This operation is usually called Unfold. There's no built-in version but it is implemented in FSharp.Core, so you could wrap that:

public static IEnumerable<T> Unfold<T, TState>(TState init, Func<TState, T> gen)
{
    var liftF = new Converter<TState, Microsoft.FSharp.Core.FSharpOption<Tuple<T, TState>>>(x =>
    {
        var r = gen(x);
        if (r == null)
        {
            return Microsoft.FSharp.Core.FSharpOption<Tuple<T, TState>>.None;
        }
        else
        {
            return Microsoft.FSharp.Core.FSharpOption<Tuple<T, TState>>.Some(Tuple.Create(r, x));
        }
    });

    var ff = Microsoft.FSharp.Core.FSharpFunc<TState, Microsoft.FSharp.Core.FSharpOption<Tuple<T, TState>>>.FromConverter(liftF);
    return Microsoft.FSharp.Collections.SeqModule.Unfold<TState, T>(ff, init);
}

public static IEnumerable<T> Unfold<T>(T source, Func<T, T> func)
{
    return Unfold<T>(source, func);
}

however writing your own version would be simpler:

public static IEnumerable<T> Unfold<T>(T source, Func<T, T> func)
{
    T current = source;
    while(current != null)
    {
        yield return current;
        current = func(current);
    }
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download