C#的LINQ是否存在等价于F# Seq.scan的方法?
答案
.NET 6及更高版本的System.Linq中已经提供了与F# Seq.scan完全等价的Enumerable.Scan方法,包含两种重载:
1. 带初始值的重载(对应Seq.scan)
需要传入初始聚合值,返回包括初始值在内的每一步聚合结果:
using System.Linq; var numbers = new[] { 1, 2, 3, 4 }; // 以0为初始值,计算累加的每一步 var cumulativeSums = numbers.Scan(0, (accumulated, current) => accumulated + current); // 输出结果:0, 1, 3, 6, 10 foreach (var sum in cumulativeSums) { Console.WriteLine(sum); }
2. 无初始值的重载(类似Seq.reduce的扫描版本)
无需初始值,以序列的第一个元素作为初始聚合值,返回后续每一步的聚合结果:
using System.Linq; var numbers = new[] { 1, 2, 3, 4 }; // 以第一个元素为初始值,计算累加的每一步 var cumulativeSums = numbers.Scan((accumulated, current) => accumulated + current); // 输出结果:1, 3, 6, 10 foreach (var sum in cumulativeSums) { Console.WriteLine(sum); }
如果使用.NET 5及更早版本
核心类库没有内置Scan方法,你可以自行实现扩展方法:
带初始值的扩展方法
public static class EnumerableExtensions { public static IEnumerable<TResult> Scan<TSource, TResult>(this IEnumerable<TSource> source, TResult seed, Func<TResult, TSource, TResult> accumulator) { if (source == null) throw new ArgumentNullException(nameof(source)); if (accumulator == null) throw new ArgumentNullException(nameof(accumulator)); yield return seed; var current = seed; foreach (var item in source) { current = accumulator(current, item); yield return current; } } }
无初始值的扩展方法
public static class EnumerableExtensions { public static IEnumerable<TSource> Scan<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> accumulator) { if (source == null) throw new ArgumentNullException(nameof(source)); if (accumulator == null) throw new ArgumentNullException(nameof(accumulator)); using var enumerator = source.GetEnumerator(); if (!enumerator.MoveNext()) yield break; var current = enumerator.Current; yield return current; while (enumerator.MoveNext()) { current = accumulator(current, enumerator.Current); yield return current; } } }
你也可以选择使用LanguageExt库中的Scan方法,但如果优先使用核心类库,以上自行实现的方式完全满足需求。
内容的提问来源于stack exchange,提问作者Lyndon Gingerich
相关产品推荐
相关产品推荐

