patterncsharpMinor
Splicing enumerables together
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]
A
Here is the actual splice code. Don't worry about what an
```
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
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:
Produces output
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.
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-6Note 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-6Context
StackExchange Code Review Q#133982, answer score: 4
Revisions (0)
No revisions yet.