使用函数创建集合以获取下一个成员

时间:2017-03-22 19:29:34

标签: c#

我需要根据任意函数将值累积到集合中。每个值都来自于对前一个值调用函数。

我目前的尝试:

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();
}

是否有内置的.Net Framework功能来执行此操作?

2 个答案:

答案 0 :(得分:1)

此操作通常称为Unfold。没有内置版本,但它在FSharp.Core中实现,因此您可以将其包装起来:

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);
}

然而编写自己的版本会更简单:

public static IEnumerable<T> Unfold<T>(T source, Func<T, T> func)
{
    T current = source;
    while(current != null)
    {
        yield return current;
        current = func(current);
    }
}

答案 1 :(得分:-1)

你指的是anamorphism这里提到的Unfold,这是一种互为性的双重性。

Aggregatelinq-unfold-operator的双重身份。 {。1}}存在于.Net Framework中; Unfold没有(出于某种未知原因)。因此你的困惑。

/// seeds: the initial data to unfold
/// stop: if stop(seed) is True, don't go any further
/// map: transform the seed into the final data
/// next: generate the next seed value from the current seed 
public static IEnumerable<R> UnFold<T,R>(this IEnumerable<T> seeds, Predicate<T> stop, 
                                         Func<T,R> map, Func<T,IEnumerable<T>> next) {
    foreach (var seed in seeds) {
        if (!stop(seed)) {
            yield return map(seed);
            foreach (var val in next(seed).UnFold(stop, map, next))
                yield return val; 
        }
    }
}

用法示例:

var parents = new[]{someType}.UnFold(t => t == null, t => t, 
                                     t => t.GetInterfaces().Concat(new[]{t.BaseType}))
                             .Distinct();