Skip to content
David Arno edited this page Feb 17, 2020 · 2 revisions

Cycle methods

Endlessly repeating enumerations


Introduction to Cycle methods

The Cycle() methods endlessly repeat an enumerable sequence. It comes in two flavours:

IEnumerable<T> extension method

public static IEnumerable<T> Cycle<T>(this IEnumerable<T> collection)

Method taking the list of items as parameters

public static IEnumerable<T> Cycle<T>(params T[] collection)

In both cases, Cycle() will return an IEnumerable<T> which will yield each element of the collection in turn, before looping back to the start and re-yielding them. The items are cached as they are yielded, therefore subsequence re-yields do not re-enumerate the enumerable.

Example of use

Let's say we have a need to provide a method that endlessly repeats a British traffic light sequence of green, amber, red, red-and-amber and back to green.

We'll define some basic types first:

public enum LightState
{
    Off,
    On
}

public struct Lights
{
    public LightState Red { get; }
    public LightState Amber { get; }
    public LightState Green { get; }

    public Lights(LightState red, LightState amber, LightState green)
        => (Red, Amber, Green) = (red, amber, green);
}

Now let's consider a fairly typical imperative implementation:

private enum LightsStage
{
    Green,
    Amber,
    Red,
    RedAmber
}

public static IEnumerable<Lights> SequenceTrafficLightImperative()
{
    var state = LightsStage.Green;
    while (true)
    {
        switch (state)
        {
            case LightsStage.Green:
                yield return new Lights(LightState.Off, LightState.Off, LightState.On);
                state = LightsStage.Amber;
                break;
            case LightsStage.Amber:
                yield return new Lights(LightState.Off, LightState.On, LightState.Off);
                state = LightsStage.Red;
                break;
            case LightsStage.Red:
                yield return new Lights(LightState.On, LightState.Off, LightState.Off);
                state = LightsStage.RedAmber;
                break;
            case LightsStage.RedAmber:
                yield return new Lights(LightState.On, LightState.On, LightState.Off);
                state = LightsStage.Green;
                break;
        }
    }
}

It's got the things one would typically expect of an imperative approach: a while loop, a switch statement and a constantly mutating variable, state. It's also, as is typical of imperative programming, long.

The Cycle method let's us reduce this code considerably:

public static IEnumerable<Lights> SequenceTrafficLightDeclarative()
    => new List<Lights> {
        new Lights(LightState.Off, LightState.Off, LightState.On),
        new Lights(LightState.Off, LightState.On, LightState.Off),
        new Lights(LightState.On, LightState.Off, LightState.Off),
        new Lights(LightState.On, LightState.On, LightState.Off)
    }.Cycle();

We simply declare a sequence list and use Cycle to repeat it. We have reduced the whole thing to one (admittedly long, if we really did put it on one line) line of code and so we can even use the expression body notation (=>) for it.

Clone this wiki locally