CodeThinked

codethinked (kōdthĭngked) adj. To be consumed by or obsessed with code.

Zip method added to Dizzy

I just checked in a Zip method to Dizzy. This method takes n number of lists and returns a list of lists containing the nth item in each list. Go that? Ha. Let me show you:

image

Did that clear it up? Good. Lets take a quick look at the code (before you freak out, scroll down below the code):

public static IEnumerable<T[]> Zip<T>(this IEnumerable<T> list, params IEnumerable<T>[] lists)
{
    if (list == null) throw new ArgumentNullException("list");
 
    int enumeratorsCount = lists == null ? 1 : lists.Length + 1;
 
    var enumerators = new IEnumerator<T>[enumeratorsCount];
    enumerators[0] = list.GetEnumerator();
 
    if (lists != null)
    {
        for (int i = 0; i < lists.Length; i++)
        {
            if (lists[i] == null)
                throw new ArgumentNullException("lists", 
                    String.Format("Item at index {0} is null", i));
            enumerators[i + 1] = lists[i].GetEnumerator();
        }    
    }            
 
    return ZipImplementation(enumeratorsCount, enumerators);
}
private static IEnumerable<T[]> ZipImplementation<T>(int enumeratorsCount, IEnumerable<IEnumerator<T>> enumerators)
{
    for (;;)
    {
        int current = 0;
        var result = new T[enumeratorsCount];
        foreach (var enumerator in enumerators)
        {
            if (!enumerator.MoveNext())
                yield break;
            result[current++] = enumerator.Current;
        }
        yield return result;
    }
}

Look a little crazy? Why is it two methods? Well, the first method basically just gets a list of all enumerators that we are going to loop through. It also checks the list to see if it is null. This method exists so that all of these checks will be done when the method is first called. Then we call ZipImplementation which uses "yield return" and so it is not executed right away. ZipImplementation is what does all of the heavy lifting for the function. It loops through the array of enumerators adding each item to the current sub list in our result. If we run out of items in any iterator then we just call "yield break" and quit.

If we successfully fill the current array then we "yield return" it. And that is pretty much it, I hope you find the method useful and go check out Dizzy if you feel the urge!