我有一串数字:
var seq = new List<int> { 1, 3, 12, 19, 33 };
我想把它转换成一个新的序列把这个数字加到前面的数字上来创建一个新的序列
{ 1, 3, 12, 19, 33 } --> {1, 4, 16, 35, 68 }
我想出了下面的方法,但是我不喜欢状态变量'count',我也不喜欢我使用值Enumerable而不对它进行操作的事实。
int count = 1;
var summed = values.Select(_ => values.Take(count++).Sum());
还能怎么办呢?
8条答案
按热度按时间rt4zxlrg1#
这是函数式编程中的一种常见模式,在F#中称为scan。它类似于C#的Enumerable.Aggregate和F#的fold,只是它在生成最终结果的沿着生成累加器的中间结果。我们可以用一个扩展方法很好地在C#中实现scan:
然后按如下方式使用它:
pgpifvop2#
“纯”LINQ:
var result = seq.Select((a, i) => seq.Take(i + 1).Sum());
O(n)时间复杂度:
还有一个LINQ,带有状态维护:
efzxgjgh3#
Stephen Swensen的回答很好,scan正是你所需要的,还有另一个版本的scan,虽然它不需要种子,但它会稍微更适合你的问题。
这个版本要求输出元素类型与输入元素类型相同,在您的例子中就是这样,并且提供了不需要传入0然后跳过第一个(0)结果的优点。
您可以在C#中实现此版本的扫描,如下所示:
然后按如下方式使用它:
jslywgbw4#
xzabzqsa5#
为了提供另一种替代方法(虽然不是真正的LINQ),您可以编写一个基于yield的函数来进行聚合:
像BrokenGlass一样,这只对数据进行了一次传递,尽管与他不同的是,返回的是迭代器而不是列表。
(真烦人。)
epggiuax6#
要使用Linq并且只在可以使用自定义聚合器时遍历列表:
..
sqserrrh7#
dddzy1tm8#
所有已经发布的答案都运行良好。我只想补充两件事:
{ if(!input.Any())收益率中断;
}
运行良好,但由于对集合的多次访问,很可能比使用@Nathan菲利普斯版本效率低。枚举可能做得更好。