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

I have the following list of different lines:

"A"
"B"
"C"

If I want an element 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 seems to me that there is a better way to go about this ( may be?).

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 definitely discover LINQ-esque's way of doing this as well :)

+8
list c # enumeration linq
source share
7 answers

I think you can change the line

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

for something like

 return items[(index + 1) % items.Count]; 
+6
source share

The solution you have is functionally correct, but its performance is poor. Usually, when you work with a list style structure, you expect GetNext return the result in O (1) time, but 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 
+7
source share

I see some optimization if you track the current index, and not the current row, but for this you will need to fix the list of elements, i.e. don't change.

You can also return items[(index + 1) % items.Count];

Otherwise, this code looks good to me, but maybe someone has a smarter solution.

+1
source share

LINQ is not a suitable tool here.

It sounds like LinkedList<T> will be the best collection here:

 var linkedItems = new LinkedList<String>(items); LinkedListNode current = linkedItems.Find("C"); String afterC = current.Next == null ? linkedItems.First.Value : current.Next.Value; 

Here are the pros and cons of LinkedList compared to the list.

+1
source share

Linus path:

 var result = (from str in list let index = list.IndexOf(curr) + 1 select list.ElementAtOrDefault(index) ?? list[0]).First(); 
+1
source share

You can use the mod statement to simplify this and combine everything into one statement:

 return items[((String.IsNullOrWhitespace(curr) ? 0 : items.IndexOf(curr)) + 1) % items.Count] 

Its definitely shorter, but I'm not sure if its more readable either :)

0
source share

I think the best solution is in the link below, I tried it and worked like a charm.

http://www.dotnetperls.com/sort-list

0
source share

All Articles