Enrique Moreno Tent
Enrique Moreno Tent

Reputation: 25267

Circular lists in C#

I am not very experienced with C#. I am trying to build circular lists and I have done it like this:

public List<string> items = new List<string> {"one", "two", "three"};
private int index = 0;

void nextItem() {
    if (index < items.Count - 1)
        index += 1;
    else
        index = 0;

    setItem();
}

void previousItem() {
    if (index > 0)
        index -= 1;
    else
        index = items.Count - 1;

    setItem();
}

void Update() {
         if (Input.GetKeyDown(KeyCode.RightArrow)) nextItem();
    else if (Input.GetKeyDown(KeyCode.LeftArrow))  previousItem();
}

But now I am wondering: Am I reinventing the wheel? Does C# already come with a proper data structure for this?

EDIT: In case some context is needed. I have a game menu, where I display a collection of items, and I want that when I press "next" and Im at the last one, to show the first item again.

Upvotes: 16

Views: 21667

Answers (3)

mbcom
mbcom

Reputation: 188

You can also write your own circular list

public class CircularList<T> : List<T>, IEnumerable<T>
{
    public new IEnumerator<T> GetEnumerator()
    {
        return new CircularEnumerator<T>(this);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return new CircularEnumerator<T>(this);
    }
}

class CircularEnumerator<T> : IEnumerator<T>
{
    private readonly List<T> list;
    int i = 0;

    public CircularEnumerator(List<T> list){
        this.list = list;
    }

    public T Current => list[i];

    object IEnumerator.Current => this;

    public void Dispose()
    {
        
    }

    public bool MoveNext()
    {
        i = (i + 1) % list.Count;
        return true;
    }

    public void Reset()
    {
        i = 0;
    }
}

Upvotes: 4

Zanyar Jalal
Zanyar Jalal

Reputation: 1874

    public class CircularList<T> : List<T>
    {
        private int Index;

        public CircularList() : this(0) { }

        public CircularList(int index)
        {
            if (index < 0 || index >= Count)
                throw new Exception(string.Format("Index must between {0} and {1}", 0, Count));

            Index = index;
        }

        public T Current()
        {
            return this[Index];
        }

        public T Next()
        {
            Index++;
            Index %= Count;

            return this[Index];
        }

        public T Previous()
        {
            Index--;
            if (Index < 0)
                Index = Count - 1;

            return this[Index];
        }

        public void Reset()
        {
            Index = 0;
        }

        public void MoveToEnd()
        {
            Index = Count - 1;
        }

    }

Upvotes: 1

Binkan Salaryman
Binkan Salaryman

Reputation: 3048

With utilization of the % (remainder) operator your code gets quite simple:

void nextItem() {
    index++; // increment index
    index %= items.Count; // clip index (turns to 0 if index == items.Count)
    // as a one-liner:
    /* index = (index + 1) % items.Count; */

    setItem();
}

void previousItem() {
    index--; // decrement index
    if(index < 0) {
        index = items.Count - 1; // clip index (sadly, % cannot be used here, because it is NOT a modulus operator)
    }
    // or above code as a one-liner:
    /* index = (items.Count+index-1)%items.Count; */ // (credits to Matthew Watson)

    setItem();
}

Upvotes: 16

Related Questions