Skip to content

Commit

Permalink
Refactor "Interleave" to use linked list
Browse files Browse the repository at this point in the history
This is a squashed merge of PR #726.

Co-authored-by: Atif Aziz <[email protected]>
  • Loading branch information
Orace and atifaziz authored Jan 14, 2023
1 parent 1fc1e31 commit 4c583f2
Showing 1 changed file with 27 additions and 26 deletions.
53 changes: 27 additions & 26 deletions MoreLinq/Interleave.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,54 +50,55 @@ public static IEnumerable<T> Interleave<T>(this IEnumerable<T> sequence, params
if (otherSequences.Any(s => s == null))
throw new ArgumentNullException(nameof(otherSequences), "One or more sequences passed to Interleave was null.");

return _(); IEnumerable<T> _()
return _(otherSequences.Prepend(sequence));

static IEnumerable<T> _(IEnumerable<IEnumerable<T>> sequences)
{
var sequences = new[] { sequence }.Concat(otherSequences);
var enumerators = new List<IEnumerator<T>?>();
var enumerators = new LinkedList<IEnumerator<T>>();

try
{
foreach (var enumerator in sequences.Select(s => s.GetEnumerator()))
// First, yield first element of each sequence.

foreach (var sequence in sequences)
{
enumerators.Add(enumerator);
var enumerator = sequence.GetEnumerator();

enumerators.AddLast(enumerator);
if (enumerator.MoveNext())
{
yield return enumerator.Current;
}
else
else // Dispose and remove empty sequence
{
enumerators.Remove(enumerator);
enumerator.Dispose();
enumerators.Remove(enumerator);
}
}

var hasNext = true;
while (hasNext)
// Then, yield remaining elements from each sequence.

var node = enumerators.First;
while (node is { Value: var enumerator, Next: var nextNode })
{
hasNext = false;
for (var i = 0; i < enumerators.Count; i++)
if (enumerator.MoveNext())
{
var enumerator = enumerators[i];
if (enumerator == null)
continue;

if (enumerator.MoveNext())
{
hasNext = true;
yield return enumerator.Current;
}
else
{
enumerators[i] = null;
enumerator.Dispose();
}
yield return enumerator.Current;
}
else
{
enumerator.Dispose();
enumerators.Remove(node);
}

// Work on next node or restart from first one.
node = nextNode ?? enumerators.First;
}
}
finally
{
foreach (var enumerator in enumerators)
enumerator?.Dispose();
enumerator.Dispose();
}
}
}
Expand Down

0 comments on commit 4c583f2

Please sign in to comment.