так вот интересная проблема. я пытаюсь использовать функциональный подход для решения чего-то, что было бы очень просто в императивном порядке. цель состоит в том, чтобы взять последовательность и свернуть/свести ее к одному значению, однако я хочу остановиться и выйти раньше, как только накопленное значение удовлетворяет заданному условию. вы можете сказать, что я хочу определить IEnumerable<T>.AggregateUntil
. вот как я бы написать это в императивной моде:Функциональное программирование: функция AggregateUntil
public static TAccumulate AggregateUntil<TSource, TAccumulate>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TSource, TAccumulate, TAccumulate> accumulate,
Func<TAccumulate, bool> until)
{
var result = seed;
foreach (var s in source)
{
result = accumulate(s, result);
if (until(result))
{
break;
}
}
return result;
}
как бы вы о написании, что в функциональном стиле, без петли foreach
? я специально пытаюсь найти способ сделать это таким образом, чтобы не заставлять меня повторно внедрять Aggregate
в целом, с этой маленькой разницей в поведении. Я также хотел бы сделать это, не повторяя сбор дважды. Я все еще работаю над этим и опубликую обновление, если я это выясню, но если кто-то там захочет помочь с вызовом, который тоже приветствуется.
EDIT # 1:
вот удар, как реализовать это без Until
концепции, просто для того чтобы получить соков:
private static TAccumulate AggregateUntil<TSource, TAccumulate>(
IEnumerable<TSource> source,
TAccumulate seed,
Func<TSource, TAccumulate, TAccumulate> accumulate)
{
using (var enumerator = source.GetEnumerator())
{
return AggregateUntil(enumerator, seed, accumulate);
}
}
private static TAccumulate AggregateUntil<TSource, TAccumulate>(
IEnumerator<TSource> source,
TAccumulate seed,
Func<TSource, TAccumulate, TAccumulate> accumulate)
{
return source.MoveNext()
? AggregateUntil(source, accumulate(source.Current, seed), accumulate, until)
: seed;
}
EDIT # 2:
OK, I «Я реализовал свою целевую функцию по функциональности, но я еще не понял, как это сделать, не переосмысливая в основном всю логику foldl/reduce/aggregate + до состояния. Я чувствую, что не хватает основной трюк FP компонуемости, если я не могу понять, как повторно использовать логику в Aggregate
как есть:
private static TAccumulate AggregateUntil<TSource, TAccumulate>(
IEnumerable<TSource> source,
TAccumulate seed,
Func<TSource, TAccumulate, TAccumulate> accumulate,
Func<TAccumulate, bool> until)
{
using (var enumerator = source.GetEnumerator())
{
return AggregateUntil(enumerator, seed, accumulate, until);
}
}
private static TAccumulate AggregateUntil<TSource, TAccumulate>(
IEnumerator<TSource> source,
TAccumulate seed,
Func<TSource, TAccumulate, TAccumulate> accumulate,
Func<TAccumulate, bool> until)
{
TAccumulate result;
return source.MoveNext()
? until(result = accumulate(source.Current, seed))
? result
: AggregateUntil(source, result, accumulate, until)
: seed;
}
Ничего особенного, но общего совета I, который я получил при попытке выйти из складки/накопления на основе некоторого состояния, заключается в использовании recucrsion. – smk