2012-09-19 30 views
12

क्या सी # में पहले से ही कोई फ़ंक्शन है जो "सशर्त ज़िप" कर सकता है?क्या सी # में पहले से ही एक सशर्त ज़िप कार्य है?

आईई।

क्या कोई ऐसा फ़ंक्शन है जो अलग-अलग लंबाई इनपुट की अनुमति देता है और एक अनुमान लगाता है जो छोटे स्रोतों को बढ़ाने के लिए निर्धारित करता है, जैसे कि बड़े स्रोत में सभी तत्वों को देखा जाता है?

एक प्रदूषित उदाहरण के रूप में, मान लीजिए कि हमारे पास प्राइम संख्याओं का एक बड़ा हिस्सा है और पूर्णांक के समेकित (दोनों आरोही आरोही) हैं। हम एक नए गणित का उत्पादन करना चाहते हैं जो पिछले प्रधान के बाद से प्रमुख और सभी पूर्णांक धारण करता है।

{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); 
     } 
    } 
} 

यह गारंटी देता है कि दोनों enumerations केवल एक बार प्रगणित कर दिया जाएगा।

उपयोग:

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

यह मान्य है और मेरे उत्तर की तुलना में ओ (एन) (एन: src2.Count()) जैसा लगता है, इतना बेहतर है। –

+0

@EvrenKuzucuoglu हालांकि '.ToArray();' ओ (एन) ऑपरेशन है और इसलिए 'क्लीयर() 'है। – Magnus

+0

मैंने इस विचार और ज़िप के स्रोत को लिया और समाधान बनाया। इसे उत्तर के रूप में चिह्नित किया। –

4

यह एक अच्छा है। मुझे नहीं लगता कि आपको सीधे तैयार किए गए फ़ंक्शन को .NET के भीतर मिल जाएगा, लेकिन यदि आप चाहते हैं कि ऑपरेशन गणित में एक मानक कार्रवाई है, तो मुझे यकीन है कि कहीं भी एक पुस्तकालय है जो ऐसा करता है। यदि आप इसे स्वयं करना चाहते हैं, हालांकि, आप समूह का उपयोग कर सकते हैं। इस विशेष परिदृश्य में:

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) 
    }; 

यह एक साधारण पर्याप्त समाधान की तरह लगता है। यह इसमें दो सदस्यों के साथ एक अनौपचारिक प्रकार का एक गणना करेगा। आप एक शब्दकोश में बदलने के कर सकते हैं:

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

संपादित करें: अभाज्य यह काम करने के लिए आदेश दिया जा करने के लिए किया है।

+0

धन्यवाद, मुझे नहीं पता था कि आप ऐसा कर सकते हैं! हालांकि मुझे ज़िप की तरह कुछ चाहिए जो केवल एक बार बताता है। मैं गारंटी नहीं दे सकता कि संख्याओं को एक से अधिक बार समझा जा सकता है। –

+1

वास्तव में इस मामले में एल्गोरिदम ओ (एन * पी) जैसा कुछ है, इसलिए सहजता से मैं इष्टतम नहीं कहूंगा। यदि आप एक विशिष्ट इष्टतम एल्गोरिदम जानते थे, लेकिन ऐसा कोई कारण नहीं है कि आपको मानक लूप के साथ इसे लागू करने में सक्षम नहीं होना चाहिए। –

0

यह है कि मैं क्या साथ (बदसूरत कार्यान्वयन) चला गया लेकिन केवल एक बार enumerables विश्लेषण करता है।

/// <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 = संख्यात्मक। श्रेणी (1, 20)। थ्रोआईफ्यूनेटेड मॉरहान (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();