Last active
August 29, 2015 14:23
-
-
Save dwcullop/e042ab8904681691cb7d to your computer and use it in GitHub Desktop.
Class that implements extension methods for Interleaving multiple collections into one collection.(e.g. [A, A, A,] + [B, B, B] = [A, B, A, B, A, B])
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Globalization; | |
using System.Linq; | |
namespace DareWare.Utils.Extensions | |
{ | |
/// <summary> | |
/// Interleave (v.): To intersperse (something) at regular intervals between parts of a thing | |
/// Source: http://en.wiktionary.org/wiki/interleave#Verb | |
/// </summary> | |
static public class CollectionInterleave | |
{ | |
#region Main Worker Methods | |
/// <summary> | |
/// Takes a collection of enumerables and returns a single enumerable with the contents of the inputs | |
/// interleaved together. If the input enumerables are [1, 1, 1] and [2, 2, 2, 2, 2] then the output will be | |
/// [1, 2, 1, 2, 1, 2, 2, 2]. | |
/// </summary> | |
/// <typeparam name="T">The datatype of the collection contents</typeparam> | |
/// <param name="enumerables">The collection of collections to be interwoven</param> | |
/// <returns>A collection with the contents of all of the source collections interleaved together</returns> | |
/// <exception cref="System.ArgumentNullException">Thrown if all of the input IEnumerables are NULL</exception> | |
static public IEnumerable<T> Interleave<T>( IEnumerable<IEnumerable<T>> enumerables ) | |
{ | |
// Get an enumerator for each non-null enumerable | |
var enumerators = enumerables.Where( w => (w != null) ) | |
.Select( s => s.GetEnumerator() ) | |
.ToList(); | |
try | |
{ | |
var active = enumerators.AsEnumerable(); | |
// Reduce the collection down to the ones where MoveNext is true | |
while ( (active = active.Where( w => w.MoveNext() ).ToArray()).Any() ) | |
{ | |
// For each of those, return one value each | |
foreach ( var c in active ) | |
{ | |
yield return c.Current; | |
} | |
} | |
} | |
finally | |
{ | |
// When all done, dispose each enumerator | |
foreach ( var d in enumerators ) | |
{ | |
d.Dispose(); | |
} | |
} | |
} | |
#endregion Main Worker Methods | |
#region Extension Methods | |
/// <inheritdoc /> | |
/// <remarks> | |
/// Syntactic sugar to make the above overload more fun to call. Enables syntax such as: | |
/// <c>coll1.Interleave( coll2, coll3 );</c> which interleaves the three collections together. | |
/// </remarks> | |
/// <param name="first">The first collection to be interleaved</param> | |
/// <param name="others">Array of other collections to be interleaved</param> | |
static public IEnumerable<T> Interleave<T>( this IEnumerable<T> first, params IEnumerable<T>[] others ) | |
{ | |
if ( first == null ) | |
{ | |
throw new ArgumentNullException( "first", "The 'this' parameter cannot be NULL" ); | |
} | |
return Interleave<T>( Enumerable.Repeat( first, 1 ).Concat( others ) ); | |
} | |
#endregion Extension Methods | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I needed this today so I whipped it up. Now it turns out I don't need it... 😬 So I'm sharing to make sure that time wasn't wasted and at least someone can benefit from it. If this helps you, let me know.