用于IEnumerable的C#实现的F#Seq模块?

F#有一堆标准的序列运算符,我从Mathematica的经验中了解和喜爱。 F#现在得到了很多关注,当它一般发布时,我打算经常使用它。

现在,由于F#尚未普遍发布,我无法在生产代码中真正使用它。 LINQ使用类似SQL的名称来实现其中一些运算符(例如’select’是’map’,’where’是’filter’),但我找不到’fold’,’iter’或’partition’的实现。

有没有人见过标准序列运算符的C#实现? 这是某人应该写的东西吗?

如果仔细观察,许多Seq操作都具有LINQ等效或可以轻松派生。 只是看下面的清单 ……

  • Seq.append = Concat(IEnumerable second)

  • Seq.concat = SelectMany, TResult>(s => s)

  • Seq.distinct_by = GroupBy(keySelector).Select(g => g.First())

  • Seq.exists = Any(Func predicate)

  • Seq.mapi = Select(Func selector)

  • Seq.fold = Aggregate(TAccumulate seed, Func func)

List.partition定义如下:

将集合拆分为两个集合,其中包含给定谓词分别返回truefalse的元素

我们可以使用GroupBy和一个双元素数组作为穷人的元组来实现:

 public static IEnumerable[] Partition(this IEnumerable source, Func predicate) { return source.GroupBy(predicate).OrderByDescending(g => g.Key).ToArray(); } 

元素0保存真实值; 1保存虚假值。 GroupBy基本上是类固醇的分区。

最后, Seq.iterSeq.iteri很容易映射到foreach:

 public static void Iter(this IEnumerable source, Action action) { foreach (var item in source) action(item); } public static void IterI(this IEnumerable source, Action action) { int i = 0; foreach (var item in source) action(i++, item); } 
  • fold = Aggregate

告诉我们使用iterpartition做什么,我们可以填写空白。 我猜iter = SelectMany和分区可能涉及Skip / Take


(更新)我查找分区 – 这是一个粗略的实现,它做了一些:

 using System; using System.Collections.Generic; static class Program { // formatted for space // usage static void Main() { int[] data = { 1, 2, 3, 4, 5, 6 }; var qry = data.Partition(2); foreach (var grp in qry) { Console.WriteLine("---"); foreach (var item in grp) { Console.WriteLine(item); } } } static IEnumerable> Partition( this IEnumerable source, int size) { int count = 0; T[] group = null; // use arrays as buffer foreach (T item in source) { if (group == null) group = new T[size]; group[count++] = item; if (count == size) { yield return group; group = null; count = 0; } } if (count > 0) { Array.Resize(ref group, count); yield return group; } } } 

iter作为List类中的方法存在,即ForEach

除此以外 :

 public static void iter(this IEnumerable source, Action act) { foreach (var item in source) { act(item); } } 

ToLookup可能是List.partition的更好匹配:

 IEnumerable sequence = SomeSequence(); ILookup lookup = sequence.ToLookup(x => SomeCondition(x)); IEnumerable trueValues = lookup[true]; IEnumerable falseValues = lookup[false]; 

在C#中滚动你自己是一个有趣的练习,这里有一些我的。 (另见这里 )

请注意,IEnumerable上的iter / foreach略有争议 – 我认为因为你必须’敲定’(或任何单词)IEnumerable以便实际发生任何事情。

  //mimic fsharp map function (it's select in c#) public static IEnumerable Map(this IEnumerable input, Func func) { foreach (T val in input) yield return func(val); } //mimic fsharp mapi function (doens't exist in C#, I think) public static IEnumerable MapI(this IEnumerable input, Func func) { int i = 0; foreach (T val in input) { yield return func(i, val); i++; } } //mimic fsharp fold function (it's Aggregate in c#) public static TResult Fold(this IEnumerable input, Func func, TResult seed) { TResult ret = seed; foreach (T val in input) ret = func(val, ret); return ret; } //mimic fsharp foldi function (doens't exist in C#, I think) public static TResult FoldI(this IEnumerable input, Func func, TResult seed) { int i = 0; TResult ret = seed; foreach (T val in input) { ret = func(i, val, ret); i++; } return ret; } //mimic fsharp iter function public static void Iter(this IEnumerable input, Action action) { input.ToList().ForEach(action); } 

以下是dahlbyk partition解决方案的更新。

它返回一个array[] ,其中“element 0保存真值; 1保存false值” – 但是当所有元素匹配或者所有谓词都失败时,这不成立,在这种情况下你有一个单例数组,痛苦的世界。

 public static Tuple, IEnumerable> Partition(this IEnumerable source, Func predicate) { var partition = source.GroupBy(predicate); IEnumerable matches = partition.FirstOrDefault(g => g.Key) ?? Enumerable.Empty(); IEnumerable rejects = partition.FirstOrDefault(g => !g.Key) ?? Enumerable.Empty(); return Tuple.Create(matches, rejects); }