Reputation: 31
When am trying to while loop of Enumerator List, How to get Next and previous values. Please find the below code.
public static void Main()
{
List<string> mylist = new List<string>();
mylist.Add("C#");
mylist.Add("Java");
mylist.Add("C");
mylist.Add("C++");
// To get an Enumerator
// for the List.
List<string>.Enumerator em = mylist.GetEnumerator();
display(em);
}
static void display(IEnumerator<string> em)
{
while (em.MoveNext()) {
string val = em.Current; // Want to know Next and Previous values of current value.
Console.WriteLine(val);
}
}
Upvotes: 3
Views: 2872
Reputation: 236208
IEnumerable
does not support checking the previous and next items. It provides access only to the current item. If you want to track the previous item you should store it manually in a local variable. Or you should store two previous values and pretend that the current one is the next.
static void display(IEnumerator<string> em)
{
if (!em.MoveNext())
return;
string prev = null; // store prev
string current = null; // store current
string next = em.Current; // null <- null -> next
do
{
// move 'window' further so that next becomes current
prev = current;
current = next;
next = em.MoveNext() ? em.Current : null;
Console.WriteLine($"[{prev}] <-[{current}]-> [{next}]");
}
while (next != null);
}
Output with your test data:
"[] <-[C#]-> [Java]"
"[C#] <-[Java]-> [C]"
"]Java] <-[C]-> [C++]"
"[C] <-[C++]-> []"
But there is a data type with required functionality from the box - doubly linked list
var mylist = new LinkedList<string>(); // instead of List
mylist.AddLast("C#");
mylist.AddLast("Java");
mylist.AddLast("C");
mylist.AddLast("C++");
display(mylist );
And here you go
static void display(LinkedList<string> list)
{
var current = list.First;
while (current != null)
{
string val = current.Value;
// null if there is no next/prev value, but you can just check if node exists
string prev = current.Previous?.Value;
string next = current.Next?.Value;
Console.WriteLine(val);
current = current.Next;
}
}
Upvotes: 2
Reputation: 192
Use Something like this :
class Program
{
int position = -1;
public List<string> mylist;
public bool MoveNext()
{
position++;
return (position < mylist.Count);
}
public String GetCurrent
{
get
{
return Current;
}
}
public string GetPrevious
{
get
{
return Previous;
}
}
public String Previous
{
get
{
try
{
return mylist[position-1];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
public String Current
{
get
{
try
{
return mylist[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
void Main(string[] args)
{
mylist = new List<string>();
mylist.Add("C#");
mylist.Add("Java");
mylist.Add("C");
mylist.Add("C++");
display(mylist);
}
void display(List<string> em)
{
while (MoveNext())
{
string val = GetCurrent;
string val2 = GetPrevious;
Console.WriteLine(val);
}
}
}
Upvotes: 0
Reputation: 1062630
Enumerators, in the GetEnumerator()
sense, are forwards-only, once-only cursors over data. If you want to know the next value: use MoveNext()
and look. If you want to know what the previous value was: you should have remembered it. Since most data structures are not doubly-linked lists, and since enumerators are not even necessarily based on data that is stored anywhere (you can do some really interesting things with iterator blocks), nothing else is possible.
In the specific case of List<T>
: perhaps use a for
loop instead of your foreach
-like enumerator access, and then you can just use list[i-1]
and list[i+1]
(after checking your boundary conditions).
Note: as a general rule, you should avoid using the enumerator APIs directly unless you are very, very familiar with what is going on underneath. Prefer foreach
or indexer-based access.
You could generalize a triplet (previous/current/next) iterator with your own iterator block; the output from { 1, 4, 5, 1, 543, 2, 1, 54, 23 }
is:
1-4-5
4-5-1
5-1-543
1-543-2
543-2-1
2-1-54
1-54-23
Code:
using System;
using System.Collections.Generic;
public static class Program
{
static void Main()
{
var data = new List<int> { 1, 4, 5, 1, 543, 2, 1, 54, 23 };
foreach(var t in data.Tripletize())
{
Console.WriteLine($"{t.Previous}-{t.Current}-{t.Next}");
}
}
static IEnumerable<Triplet<T>> Tripletize<T>(this IEnumerable<T> source)
{
using (var iter = source.GetEnumerator())
{
// read the first triple
if (!iter.MoveNext()) yield break;
var x = iter.Current;
if (!iter.MoveNext()) yield break;
var y = iter.Current;
if (!iter.MoveNext()) yield break;
var z = iter.Current;
yield return new Triplet<T>(x, y, z);
while (iter.MoveNext())
{
x = y;
y = z;
z = iter.Current;
yield return new Triplet<T>(x, y, z);
}
}
}
readonly struct Triplet<T>
{
public Triplet(T previous, T current, T next)
{
Previous = previous;
Current = current;
Next = next;
}
public T Previous { get; }
public T Current { get; }
public T Next { get; }
}
}
Upvotes: 6