2012-09-19 11 views
12

C#中是否已經有一個可以執行「條件編碼」的函數?在C#中是否已經有條件Zip函數?

I.e.

是否有一個功能,允許不同長度的輸入和花費謂詞確定何時遞增較小源枚舉,使得在較大的源的所有元素被視爲?

作爲一個人爲的例子,讓我們假設我們有質數的枚舉和整數的枚舉(均爲升序排列)。我們想要生成一個新的枚舉值,它保存自上一個素數以來的主要和所有整數。

{2, 3, 5, 7, 11} 

{1, 2, 3, 4, 5, 6, 7, 8, 9, 10,} 

{2, [1]}, {3,[]}, {5, [4]}, {7, [6]}, {11, [8,9,10]} 
+6

聽起來很有趣,但也小生,以至於我懷疑你會找到一個現成的實現。 – Jon

+0

開箱即用。 –

回答

4

我的解決辦法:

public static IEnumerable<Tuple<T1, IEnumerable<T2>>> ConditionalZip<T1, T2>(
    this IEnumerable<T1> src1, 
    IEnumerable<T2> src2, 
    Func<T1, T2, bool> check) 
{ 
    var list = new List<T2>(); 
    using(var enumerator = src2.GetEnumerator()) 
    { 
     foreach(var item1 in src1) 
     { 
      while(enumerator.MoveNext()) 
      { 
       var pickedItem = enumerator.Current; 
       if(check(item1, pickedItem)) 
       { 
        list.Add(pickedItem); 
       } 
       else 
       { 
        break; 
       } 
      } 
      var items = list.ToArray(); 
      list.Clear(); 
      yield return new Tuple<T1, IEnumerable<T2>>(item1, items); 
     } 
    } 
} 

它保證兩個枚舉系統只會記錄一次枚舉。

用法:

var src1 = new int[] { 2, 3, 5, 7, 11 }; 
var src2 = Enumerable.Range(1, 11); 
Func<int, int, bool> predicate = (i1, i2) => i1 > i2; 
var result = src1.ConditionalZip(src2, predicate); 
+0

這是有效的,並且與我的答案相比似乎是O(n)(n:src2.Count()),所以更好。 –

+0

@EvrenKuzucuoglu儘管'.ToArray();'是一個O(n)操作,'.Clear()'也是。 – Magnus

+0

我接受了這個想法和Zip的來源並提出了一個解決方案。標記爲答案。 –

4

這是一個不錯的。我不認爲你會直接在.net中找到現成的函數,但是如果你想要的操作是數學中的標準操作,我肯定有一個庫可以在某個地方執行它。如果你想自己做,但是,你可以使用group by。在這種特殊情況下:

var primes = new List<int> {2, 3, 5, 7, 11}; 
var numbers = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 

var groups = 
    from number in numbers 
    group number by primes.First(prime => prime >= number) into gnumber 
    select new { 
     prime = gnumber.Key, 
     numbers = gnumber.Where(n => n != gnumber.Key) 
    }; 

這似乎是一個足夠簡單的解決方案。它將創建一個annooymous類型的枚舉,其中有兩個成員。 你可以將其轉化爲一個字典:

var dict = groups.ToDictionary(g => g.prime, g=> g.numbers); 

編輯:質數已被責令這個工作。

+0

謝謝,我不知道你能做到這一點!不過,我需要像枚舉只有一次的Zip。我無法保證可枚舉的枚舉不止一次。 –

+1

事實上,在這種情況下,算法就像O(n * p),所以本能地說我不是最優的。如果你知道一個特定的最佳算法,儘管你沒有理由不能用標準循環來實現它。 –

0

這是我去(醜陋的實現),但列舉了可枚舉只有一次。

/// <summary> 
    /// Merges two sequences by using the specified predicate function to determine when to iterate the second enumerbale. 
    /// </summary> 
    /// 
    /// <returns> 
    /// An <see cref="T:System.Collections.Generic.IEnumerable`1"/> that contains merged elements of two input sequences. 
    /// </returns> 
    /// <param name="larger">The first sequence to merge.</param><param name="smaller">The second sequence to merge.</param> 
    /// <param name="resultSelector">A function that specifies how to merge the elements from the two sequences (a flag is passed into the dunction to notify when elements of the second source are exhausted.</param> 
    /// <typeparam name="TFirst">The type of the elements of the first input sequence.</typeparam> 
    /// <typeparam name="TSecond">The type of the elements of the second input sequence.</typeparam> 
    /// <typeparam name="TResult">The type of the elements of the result sequence.</typeparam> 
    public static IEnumerable<TResult> ConditionalZip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> larger, IEnumerable<TSecond> smaller, Func<TFirst, TSecond, bool> predicate, Func<TFirst, TSecond, bool, TResult> resultSelector) 
    { 
     if (larger == null) 
      throw new ArgumentNullException("larger"); 
     if (smaller == null) 
      throw new ArgumentNullException("smaller"); 
     if (resultSelector == null) 
      throw new ArgumentNullException("resultSelector"); 
     else 
      return ConditionalZipIterator(larger, smaller, predicate, resultSelector); 
    } 

    private static IEnumerable<TResult> ConditionalZipIterator<TFirst, TSecond, TResult>(IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, bool> predicate, Func<TFirst, TSecond, bool, TResult> resultSelector) 
    { 
     using (IEnumerator<TFirst> enumerator1 = first.GetEnumerator()) 
     { 
      using (IEnumerator<TSecond> enumerator2 = second.GetEnumerator()) 
      { 
       if (!enumerator2.MoveNext()) 
       { 
        secondIsFinished = true; 
       } 
       currentSecond = secondIsFinished ? default(TSecond) : enumerator2.Current; 

       while (enumerator1.MoveNext()) 
       { 

        while (!secondIsFinished && !predicate(enumerator1.Current, currentSecond)) 
        { 
         if (!enumerator2.MoveNext()) 
         { 
          secondIsFinished = true; 
         } 
         currentSecond = secondIsFinished ? default(TSecond) : enumerator2.Current; 
        } 


        yield return resultSelector(enumerator1.Current, currentSecond, secondIsFinished); 
       } 
      } 
     } 
    } 

的usuage

變種素數=新INT [] {2,3,5,7,11} .ThrowIfEnumeratedMoreThan(1); var ints = Enumerable.Range(1,20).ThrowIfEnumeratedMoreThan(1);

 var results = ints.ConditionalZip(primes, (i, prime) => i <= prime, (i, prime, isEmpty) => new {i, prime, wasMatched=!isEmpty}) 
      .Where(x => x.wasMatched) 
      .GroupBy(x => x.prime) 
      .Select(x => new {Prime = x.Key, Values = x.Where(n => n.i != n.prime).Select(n=>n.i).ToArray()}) 
      .ToArray(); 
相關問題