Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a better way to return the next item in a list and loop from the end to the front?

I have the following list of distinct strings:

"A"
"B"
"C"

If I want the item after A, I get B. After B, I get C. After C, I get A. Currently I have the following code, but for some reason it feels to me that there is a better way to go about this (maybe?).

private string GetNext(IList<string> items, string curr)
{
    if (String.IsNullOrWhitespace(curr))
        return items[0];

    var index = items.IndexOf(curr);
    if (index == -1)
        return items[0];

    return (index + 1 == items.Count) ? items[0] : items[index + 1];
}

I'm definitely open to a LINQ-esque way of doing this as well :)

like image 385
myermian Avatar asked Apr 23 '12 15:04

myermian


2 Answers

The solution you have is functionally correct but it's performance leaves a little to be desired. Typically when dealing with a list style structure you would expect that GetNext would return a result in O(1) time yet this solution is O(N).

public sealed class WrappingIterator<T> {
  private IList<T> _list;
  private int _index;
  public WrappingIterator<T>(IList<T> list, int index) {
    _list = list;
    _index = index;
  }
  public T GetNext() {
    _index++;
    if (_index == _list.Count) {
      _index = 0;
    }
    return _list[_index];
  }

  public static WrappingIterator<T> CreateAt(IList<T> list, T value) {
    var index = list.IndexOf(value);
    return new WrappingIterator(list, index);
  }
}

The initial call to CreateAt is O(N) here but subsequent calls to GetNext are O(1).

IList<string> list = ...;
var iterator = WrappingIterator<string>.CreateAt(list, "B");
Console.WriteLine(iterator.GetNext());  // Prints C
Console.WriteLine(iterator.GetNext());  // Prints A
Console.WriteLine(iterator.GetNext());  // Prints B
like image 193
JaredPar Avatar answered Sep 22 '22 00:09

JaredPar


I think maybe you can change the line

return (index + 1 == items.Count) ? items[0] : items[index + 1];

for something like

return items[(index + 1) % items.Count];
like image 32
Andres Avatar answered Sep 23 '22 00:09

Andres