给定一组正数和负数是否有一个可以得到中间值的Linq表达式?
例如
var heights = new List<int>();
var numbers = new [] { 5, 15, -5, -15 };
var curHeight = 0;
foreach (var number in numbers)
{
curHeight = curHeight + number;
heights.add(curHeight);
}
此功能将返回[5, 20, 15, 0]
聚合可以以相同的方式使用,它将通过此序列
numbers.aggregate((a, b) => a + b);
0 + 5 = 5, 5 + 15 = 20, 20 - 5 = 15, 15 - 15 = 0
我的问题是,有没有办法使用聚合或其他一些方法来返回中间值[5, 20, 15, 0]
?
答案 0 :(得分:14)
您需要的是聚合的自定义版本:
public static IEnumerable<R> AggregateSequence<A, R>(
this IEnumerable<A> items,
Func<A, R, R> aggregator,
R initial)
{
// Error cases go here.
R result = initial;
foreach(A item in items)
{
result = aggregator(item, result);
yield return result;
}
}
这是解决您的具体问题的一般机制:
public static IEnumerable<int> MovingSum(this IEnumerable<int> items)
{
return items.AggregateSequence( (item, sum) => item + sum, 0 );
}
现在你可以用
来解决你的问题了mySequence.MovingSum().Max();
答案 1 :(得分:2)
使用Aggregate
:
var result = numbers.Aggregate(new List<int>(), (a,b)=>
{
a.Add(a.LastOrDefault()+b);
return a;
});
结果将是:
[5,20,15,0]
如果您想拥有Max值,可以使用自定义Result类:
public class Result
{
public List<int> Values {get;set;}
public int Max => Values.Max();
public Result()
{
Values = new List<int>();
}
}
使用它:
var result = numbers.Aggregate(new Result(), (a,b)=>
{
a.Values.Add(a.Values.LastOrDefault()+b);
return a;
});
您将获得与result.Values
和[20]相同的列表result.Max
答案 2 :(得分:1)
您可以在聚合函数中执行此操作:
var intermidiateValues = new List<int>();
numbers.aggregate((intermidiateValue, next) => {
intermidiateValues.Add(intermidiateValue);
return intermidiateValue + next;
});
然后使用
intermidiateValues.Max();
答案 3 :(得分:0)
BAD性能的解决方案:
static void Main(string[] args)
{
var numbers = new[] { 5, 15, -5, -15 };
var heights = numbers.Select((o, i) => numbers.Take(i + 1).Sum()).ToList();
foreach (var item in heights)
{
Console.WriteLine(item);
}
}
它具有O(n ^ 2)复杂度。
答案 4 :(得分:0)
您可以使用自定义投影编写自己的扩展方法来执行累积/运行总计,并将其命名为:
static void Main(string[] args) {
var numbers = new[] { 5, 15, -5, -15 };
// results 5, 20, 15, 0
var results = numbers.Accumulate((a, b) => a + b);
var max = results.Max(); // 20
// providing a initial seed value: 20, 35, 30, 15:
var result2 = numbers.Accumulate(15, (a, b) => a + b);
var max2 = result2.Max(); // 35
}
扩展方法:
public static class AccumulateExt
{
public static IEnumerable<TSource> Accumulate<TSource>(
this IEnumerable<TSource> source,
Func<TSource, TSource, TSource> funcAggregate)
{
return source.Accumulate(default(TSource), funcAggregate);
}
public static IEnumerable<TAggregate> Accumulate<TSource, TAggregate>(
this IEnumerable<TSource> source,
TAggregate initialValue,
Func<TAggregate, TSource, TAggregate> funcAggregate)
{
return AccumulateImplementation(source, initialValue, funcAggregate, (_, agg) => agg);
}
public static IEnumerable<TResult> Accumulate<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TSource, TSource> funcAggregate,
Func<TSource, TSource, TResult> resultSelector)
{
return source.Accumulate(default(TSource), funcAggregate, resultSelector);
}
public static IEnumerable<TResult> Accumulate<TSource, TAggregate, TResult>(
this IEnumerable<TSource> source,
TAggregate initialValue,
Func<TAggregate, TSource, TAggregate> funcAggregate,
Func<TSource, TAggregate, TResult> resultSelector)
{
return AccumulateImplementation(source, initialValue, funcAggregate, resultSelector);
}
private static IEnumerable<TResult> AccumulateImplementation<TSource, TAggregate, TResult>(
this IEnumerable<TSource> source,
TAggregate initialValue,
Func<TAggregate, TSource, TAggregate> funcAggregate,
Func<TSource, TAggregate, TResult> resultSelector)
{
var last = initialValue;
foreach (var item in source)
{
var value = funcAggregate(last, item);
last = value;
yield return resultSelector(item, value);
}
}
}
答案 5 :(得分:-2)
单行版
var numbers = new[] { 5, 15, -5, -15 };
var curHeight = 0;
int best = numbers.Select(x => { curHeight += x; return curHeight; }).Max();
正如埃里克所指出的那样,这是一个不好的做法,即使它在这里起作用也是一种非破坏性的做法
var numbers = new[] { 5, 15, -5, -15 };
int best = Enumerable.Range(1, numbers.Length + 1).Select(x => numbers.Take(x).Sum()).Max();