Nama
Nama

Reputation: 31

How to get Next and Previous values of Enumerator List?

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

Answers (3)

Sergey Berezovskiy
Sergey Berezovskiy

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

Bahtiyar
Bahtiyar

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

Marc Gravell
Marc Gravell

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

Related Questions