2009-01-04 32 views
11

F#有一大堆標準的序列操作符,我從Mathematica的經驗中瞭解和喜愛。 F#現在吸引了我很多注意力,而當它在一般的發佈版本中時,我打算頻繁使用它。在C#中爲IEnumerable實現的F#Seq模塊?

現在,由於F#尚未發佈,因此我無法真正在生產代碼中使用它。 LINQ使用類似SQL的名稱來實現這些運算符中的一些(例如,'select'是'map','where'是'filter'),但是我找不到'fold','iter'或'partition'的實現。

有沒有人看過標準序列運算符的任何C#實現?這是某人應該寫的東西嗎?

回答

6
  • 倍= Aggregate

泰爾使用什麼iterpartition做的,我們可以填補空白。我猜iter = SelectMany和分區可能涉及Skip/Take


(更新)我擡頭Partition - 這裏的,做一些它的原油實現:

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<IEnumerable<T>> Partition<T>(
      this IEnumerable<T> 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; 
     } 
    } 
} 
1

ITER存在如清單類,這是的ForEach

否則的方法:

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

在C#中滾動自己是一個有趣的練習,這裏是af我的新聞。 (另請參閱here

請注意,對於IEnumerable而言,iter/foreach稍有爭議 - 我認爲是因爲您必須爲IEnumerable「敲定」(或任何單詞)IEnumerable才能實際發生任何事情。

//mimic fsharp map function (it's select in c#) 
    public static IEnumerable<TResult> Map<T, TResult>(this IEnumerable<T> input, Func<T, TResult> func) 
    { 
     foreach (T val in input) 
      yield return func(val); 
    } 

    //mimic fsharp mapi function (doens't exist in C#, I think) 
    public static IEnumerable<TResult> MapI<T, TResult>(this IEnumerable<T> input, Func<int, T, TResult> 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<T, TResult>(this IEnumerable<T> input, Func<T, TResult, TResult> 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<T, TResult>(this IEnumerable<T> input, Func<int, T, TResult, TResult> 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<T>(this IEnumerable<T> input, Action<T> action) 
    { 
     input.ToList().ForEach(action); 
    } 
+2

mapi等價物確實存在作爲Select的重載。此外,它似乎有點沉重的轉換您的枚舉爲列表,而不是做一個正常的foreach循環,每次調用動作... – 2009-04-14 23:19:45

+0

不知道選擇超載,謝謝你。 ToList是我想到的第一件事,我想。 – Benjol 2009-04-15 06:16:29

14

如果仔細觀察,許多Seq操作都具有LINQ等價物或可以輕鬆派生。只要往下看list ...

  • Seq.append = Concat<TSource>(IEnumerable<TSource> second)

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

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

  • Seq.exists = Any<TSource>(Func<TSource, bool> predicate)

  • Seq.mapi = Select<TSource, TResult>(Func<TSource, Int32, TResult> selector)

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

List.partition的定義如下:

拆分收集成兩個集合,包含用於所述給定謂詞返回truefalse分別

的元件,其我們可以使用GroupBy和一個兩元素數組作爲窮人的元組:

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

元素0包含真值; 1擁有虛假的價值。 GroupBy基本上是類固醇的分區。

最後,Seq.iterSeq.iteri地圖容易的foreach:

public static void Iter<TSource>(this IEnumerable<TSource> source, Action<TSource> action) 
{ 
    foreach (var item in source) 
     action(item); 
} 

public static void IterI<TSource>(this IEnumerable<TSource> source, Action<Int32, TSource> action) 
{ 
    int i = 0; 
    foreach (var item in source) 
     action(i++, item); 
} 
+0

當所有元素匹配或者所有元素都失敗時,你的分區出現問題:你會得到一個單例數組。請參閱[我的回答](http://stackoverflow.com/a/8931453/97846),受你的啓發。 – 2012-01-19 18:45:12

1

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

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

這裏是一個更新dahlbyk'spartition解決方案。

它返回了一個array[]其中「元素0保存真值; 1保存假值」—但這不適用於所有元素匹配或全部失敗的謂詞,在這種情況下,你有一個單身人士陣列和一個痛苦的世界。

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