HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Splicing enumerables together

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
enumerablessplicingtogether

Problem

Basically, what I mean by splice is to take an array of Enumerables, take the 1st element from the first one, then the 1st element from the second one, and so forth, until we come back to the 1st enumerable, and we then take the next element from it and each of the others.

Sort of like this:
[A A] [B B] [C C] [D D] [E E] [F F]
Splicing these together would produce [A B C D E F A B C D E F]

namespace xofz
{
    using System.Collections.Generic;

    public interface MaterializedEnumerable : IEnumerable
    {
        long Count { get; }
    }
}


A MaterializedEnumerable is basically an enumerable which has been written to memory, so it can be iterated as many times as you want. It also gets a Count property.

Here is the actual splice code. Don't worry about what an OrderedMaterializedEnumerable is, just think of it for now as a wrapper for List

```
namespace xofz.Transformation
{
using System.Collections.Generic;
using System.Linq;
using xofz.Materialization;

public class EnumerableSplicer
{
public MaterializedEnumerable Splice(IEnumerable[] sources)
{
var lists = new List[sources.Length];

// first, enumerate all the items into separate lists
for (var i = 0; i (new LinkedList(sources[i]));
}

// then, splice the lists together
var list = new List(lists.Sum(l => l.Count));
var smallestCount = lists.Select(l => l.Count).Min();

for (var i = 0; i l[i]));
}

var remainingLists = new LinkedList>();
foreach (var l in lists)
{
l.RemoveRange(0, smallestCount);
if (l.Count > 0)
{
remainingLists.AddLast(l);
}
}

if (remainingLists.Count == 0)
{
return new OrderedMaterializedEnumerable(list);
}

IEnumerable> remainingEnu

Solution

My comment is that you can write your desired method with far more generality, no recursion, and far less realization into lists. For example:

using System;
using System.Linq;
using System.Collections.Generic;   

public class Program
{
    public static IEnumerable Zipper(IEnumerable> sequences, Func, R> f)
    {
        var enumtors = sequences.Select(seq => seq.GetEnumerator()).ToList();
        while(true)
        {
            // Not quite kosher, as we are using Select to cause a side effect!
            var hasValues = enumtors.Select(e => e.MoveNext());
            if (hasValues.Any(v => !v)) 
                break;
            yield return f(enumtors.Select(e => e.Current));
        }
        foreach(var enumtor in enumtors)
          enumtor.Dispose();
    }

    public static void Main()
    {
        foreach(var s in Zipper(
            new[] { 
              new[] {1, 2}, 
              new[] {3, 4}, 
              new[] {5, 6, 7} }, 
            x => string.Join("-", x))) 
          Console.WriteLine(s);
    }
}


Produces output

1-3-5
2-4-6


Note that my version works on infinite lists provided that there are finitely many of them. Note also that my method is "lazy"; it only makes computations when the caller "pulls" something.

Code Snippets

using System;
using System.Linq;
using System.Collections.Generic;   

public class Program
{
    public static IEnumerable<R> Zipper<A, R>(IEnumerable<IEnumerable<A>> sequences, Func<IEnumerable<A>, R> f)
    {
        var enumtors = sequences.Select(seq => seq.GetEnumerator()).ToList();
        while(true)
        {
            // Not quite kosher, as we are using Select to cause a side effect!
            var hasValues = enumtors.Select(e => e.MoveNext());
            if (hasValues.Any(v => !v)) 
                break;
            yield return f(enumtors.Select(e => e.Current));
        }
        foreach(var enumtor in enumtors)
          enumtor.Dispose();
    }

    public static void Main()
    {
        foreach(var s in Zipper(
            new[] { 
              new[] {1, 2}, 
              new[] {3, 4}, 
              new[] {5, 6, 7} }, 
            x => string.Join("-", x))) 
          Console.WriteLine(s);
    }
}
1-3-5
2-4-6

Context

StackExchange Code Review Q#133982, answer score: 4

Revisions (0)

No revisions yet.