Exemplo n.º 1
0
        /// <summary>
        /// Interleaves the elements of two or more sequences into a single sequence, applying the specified strategy when sequences are of unequal length
        /// </summary>
        /// <remarks>
        /// Interleave combines sequences by visiting each in turn, and returning the first element of each, followed
        /// by the second, then the third, and so on. So, for example:<br/>
        /// <code>
        /// {1,1,1}.Interleave( {2,2,2}, {3,3,3} ) => { 1,2,3,1,2,3,1,2,3 }
        /// </code>
        /// This operator behaves in a deferred and streaming manner.<br/>
        /// When sequences are of unequal length, this method will use the imbalance strategy specified to
        /// decide how to continue interleaving the remaining sequences. See <see cref="ImbalancedInterleaveStrategy"/>
        /// for more information.<br/>
        /// The sequences are interleaved in the order that they appear in the <paramref name="otherSequences"/>
        /// collection, with <paramref name="sequence"/> as the first sequence.
        /// </remarks>
        /// <typeparam name="T">The type of the elements of the source sequences</typeparam>
        /// <param name="sequence">The first sequence in the interleave group</param>
        /// <param name="imbalanceStrategy">Defines the behavior of the operator when sequences are of unequal length</param>
        /// <param name="otherSequences">The other sequences in the interleave group</param>
        /// <returns>A sequence of interleaved elements from all of the source sequences</returns>

        private static IEnumerable <T> Interleave <T>(this IEnumerable <T> sequence, ImbalancedInterleaveStrategy imbalanceStrategy, params IEnumerable <T>[] otherSequences)
        {
            if (sequence == null)
            {
                throw new ArgumentNullException("sequence");
            }
            if (otherSequences == null)
            {
                throw new ArgumentNullException("otherSequences");
            }
            if (otherSequences.Any(s => s == null))
            {
                throw new ArgumentNullException("otherSequences", "One or more sequences passed to Interleave was null.");
            }

            return(InterleaveImpl(new[] { sequence }.Concat(otherSequences), imbalanceStrategy));
        }
Exemplo n.º 2
0
        /// <summary>
        /// Interleaves the elements of two or more sequences into a single sequence, applying the specified strategy when sequences are of unequal length
        /// </summary>
        /// <remarks>
        /// Interleave combines sequences by visiting each in turn, and returning the first element of each, followed
        /// by the second, then the third, and so on. So, for example:<br/>
        /// <code>
        /// {1,1,1}.Interleave( {2,2,2}, {3,3,3} ) => { 1,2,3,1,2,3,1,2,3 }
        /// </code>
        /// This operator behaves in a deferred and streaming manner.<br/>
        /// When sequences are of unequal length, this method will use the imbalance strategy specified to
        /// decide how to continue interleaving the remaining sequences. See <see cref="ImbalancedInterleaveStrategy"/>
        /// for more information.<br/>
        /// The sequences are interleaved in the order that they appear in the <paramref name="otherSequences"/>
        /// collection, with <paramref name="sequence"/> as the first sequence.
        /// </remarks>
        /// <typeparam name="T">The type of the elements of the source sequences</typeparam>
        /// <param name="sequence">The first sequence in the interleave group</param>
        /// <param name="imbalanceStrategy">Defines the behavior of the operator when sequences are of unequal length</param>
        /// <param name="otherSequences">The other sequences in the interleave group</param>
        /// <returns>A sequence of interleaved elements from all of the source sequences</returns>

        private static IEnumerable <T> Interleave <T>(this IEnumerable <T> sequence, ImbalancedInterleaveStrategy imbalanceStrategy, params IEnumerable <T>[] otherSequences)
        {
            if (sequence == null)
            {
                throw new ArgumentNullException(nameof(sequence));
            }
            if (otherSequences == null)
            {
                throw new ArgumentNullException(nameof(otherSequences));
            }
            if (otherSequences.Any(s => s == null))
            {
                throw new ArgumentNullException(nameof(otherSequences), "One or more sequences passed to Interleave was null.");
            }

            return(_()); IEnumerable <T> _()
            {
                var sequences = new[] { sequence }.Concat(otherSequences);

                // produce an iterator collection for all IEnumerable<T> instancess passed to us
                var iterators = sequences.Select(e => e.GetEnumerator()).Acquire();
                List <IEnumerator <T> > iteratorList = null;

                try
                {
                    iteratorList = new List <IEnumerator <T> >(iterators);
                    iterators    = null;
                    var shouldContinue    = true;
                    var consumedIterators = 0;
                    var iterCount         = iteratorList.Count;

                    while (shouldContinue)
                    {
                        // advance every iterator and verify a value exists to be yielded
                        for (var index = 0; index < iterCount; index++)
                        {
                            if (!iteratorList[index].MoveNext())
                            {
                                // check if all iterators have been consumed and we can terminate
                                // or if the imbalance strategy informs us that we MUST terminate
                                if (++consumedIterators == iterCount || imbalanceStrategy == ImbalancedInterleaveStrategy.Stop)
                                {
                                    shouldContinue = false;
                                    break;
                                }

                                iteratorList[index].Dispose(); // dispose the iterator sice we no longer need it

                                // otherwise, apply the imbalance strategy
                                switch (imbalanceStrategy)
                                {
                                case ImbalancedInterleaveStrategy.Pad:
                                    var newIter = iteratorList[index] = Generate(default(T), x => default(T)).GetEnumerator();
                                    newIter.MoveNext();
                                    break;

                                case ImbalancedInterleaveStrategy.Skip:
                                    iteratorList.RemoveAt(index); // no longer visit this particular iterator
                                    --iterCount;                  // reduce the expected number of iterators to visit
                                    --index;                      // decrement iterator index to compensate for index shifting
                                    --consumedIterators;          // decrement consumer iterator count to stay in balance
                                    break;
                                }
                            }
                        }

                        if (shouldContinue) // only if all iterators could be advanced
                        {
                            // yield the values of each iterator's current position
                            for (var index = 0; index < iterCount; index++)
                            {
                                yield return(iteratorList[index].Current);
                            }
                        }
                    }
                }
                finally
                {
                    Debug.Assert(iteratorList != null || iterators != null);
                    foreach (var iter in (iteratorList ?? (IList <IEnumerator <T> >)iterators))
                    {
                        iter.Dispose();
                    }
                }
            }
        }