NeedAnswers
NeedAnswers

Reputation: 1435

Get previous/next item of a given item in a List<>

Says I have this List : 1, 3, 5, 7, 9, 13

For example, given value is : 9, the previous item is 7 and the next item is 13

How can I achieve this using C#?

Upvotes: 48

Views: 143173

Answers (14)

Phil Marmotte
Phil Marmotte

Reputation: 11

Maybe extend the class List :

public static class ListExtension
{
    public static T Next<T>(this List<T> list, T elt)
    {
        int index = list.IndexOf(elt);
        index = (index == list.Count - 1) ? 0 : index + 1;
        return list[index];
    }
    public static T Prev<T>(this List<T> list, T elt)
    {
        int index = list.IndexOf(elt);
        index = (index == 0) ? list.Count - 1 : index - 1;
        return list[index];
    }
}

to use the extend functions : List<anything> list;

list.Next(elt) give the element which follows elt and list.Prev(elt) the element which precedes elt

Upvotes: 1

KyrLouca
KyrLouca

Reputation: 45

Return null if the item is not found or if it is the last element in the list

 List<string> fruits = new List<string> { "apple", "banana",  "kiwi" };
    var index = fruits.IndexOf("banana");
    var nextFruit = index==-1 ?null : fruits.Skip(index+1).FirstOrDefault();

Upvotes: 0

Mike D3ViD Tyson
Mike D3ViD Tyson

Reputation: 1771

this is a fully circle list obtained combining @Thunder and @Melad answers:

private class CircularList<T> : List<T>
    {
        private int _currentIndex = 0;
        public int CurrentIndex
        {
            get
            {
                if (_currentIndex > Count - 1) { _currentIndex = 0; }
                if (_currentIndex < 0) { _currentIndex = Count - 1; }
                return _currentIndex;
            }
            set => _currentIndex = value;
        }
        
        public int NextIndex
        {
            get
            {
                if (_currentIndex == Count - 1) return 0;
                return _currentIndex + 1;
            }
        }
        
        public int PreviousIndex
        {
            get
            {
                if (_currentIndex == 0) return Count - 1;
                return _currentIndex - 1;
            }
        }
        
        public T Next => this[NextIndex];

        public T Previous => this[PreviousIndex];

        public T MoveNext
        {
            get { _currentIndex++; return this[CurrentIndex]; }
        }

        public T MovePrevious
        {
            get { _currentIndex--; return this[CurrentIndex]; }
        }

        public T Current => this[CurrentIndex];
        
        
    }
}

check git-repo with example here

Upvotes: 2

Yurii Kot
Yurii Kot

Reputation: 326

Also if you want compact solution with circular logic without creating new list you can use following code:

int nextNumber = list[(list.IndexOf(currentNumber) + 1) % list.Count];
int previousNumber = list[(list.IndexOf(currentNumber) - 1 + list.Count) % list.Count];

https://dotnetfiddle.net/PkP2Jy

Upvotes: 9

Baro
Baro

Reputation: 5530

Using LINQ in one line and with circular search:

Next of

YourList.SkipWhile(x => x != NextOfThisValue).Skip(1).DefaultIfEmpty( YourList[0] ).FirstOrDefault();

Previous of

YourList.TakeWhile(x => x != PrevOfThisValue).DefaultIfEmpty( YourList[YourList.Count-1]).LastOrDefault();

This is a working example (link to the fiddle)

    List<string> fruits = new List<string> {"apple", "banana", "orange", "raspberry", "kiwi"};
    string NextOf = "orange";
    string NextOfIs;

    NextOfIs = fruits.SkipWhile(x => x!=NextOf).Skip(1).DefaultIfEmpty(fruits[0]).FirstOrDefault();
    Console.WriteLine("The next of " + NextOf + " is " + NextOfIs);

    NextOf = "kiwi";
    NextOfIs = fruits.SkipWhile(x => x!=NextOf).Skip(1).DefaultIfEmpty(fruits[0]).FirstOrDefault();
    Console.WriteLine("The next of " + NextOf + " is " + NextOfIs);

    string PrevOf = "orange";
    string PrevOfIs;

    PrevOfIs = fruits.TakeWhile(x => x!=PrevOf).DefaultIfEmpty(fruits[fruits.Count-1]).LastOrDefault();
    Console.WriteLine("The prev of " + PrevOf + " is " + PrevOfIs);

    PrevOf = "apple";
    PrevOfIs = fruits.TakeWhile(x => x!=PrevOf).DefaultIfEmpty(fruits[fruits.Count-1]).LastOrDefault();
    Console.WriteLine("The prev of " + PrevOf + " is " + PrevOfIs);

Upvotes: 41

Melad
Melad

Reputation: 935

To make it a kind of Circular list, try this:

public class NavigationList<T> : List<T>
{
    private int _currentIndex = -1;
    public int CurrentIndex
    {
        get
        {
            if (_currentIndex == Count)
                _currentIndex = 0;
            else if (_currentIndex > Count - 1)
                _currentIndex = Count - 1;
            else if (_currentIndex < 0)
                _currentIndex = 0;


            return _currentIndex;
        }

        set { _currentIndex = value; }
    }

    public T MoveNext
    {
        get { _currentIndex++; return this[CurrentIndex]; }
    }

    public T Current
    {
        get { return this[CurrentIndex]; }
    }
}

Upvotes: 2

Thunder
Thunder

Reputation: 11016

I have implemented this by Inheriting the .Net List

public class NavigationList<T> : List<T>
    {
        private int _currentIndex = 0;
        public int CurrentIndex
        {
            get
            {
                if (_currentIndex > Count - 1) { _currentIndex = Count - 1; }
                if (_currentIndex < 0) { _currentIndex = 0; }
                return _currentIndex;
            }
            set { _currentIndex = value; }
        }

        public T MoveNext
        {
            get { _currentIndex++; return this[CurrentIndex]; }
        }

        public T MovePrevious
        {
            get { _currentIndex--; return this[CurrentIndex]; }
        }

        public T Current
        {
            get { return this[CurrentIndex]; }
        }
    }

Using this becomes quite easy

 NavigationList<string> n = new NavigationList<string>();
            n.Add("A");
            n.Add("B");
            n.Add("C");
            n.Add("D");
            Assert.AreEqual(n.Current, "A");
            Assert.AreEqual(n.MoveNext, "B");
            Assert.AreEqual(n.MovePrevious, "A");

Upvotes: 13

fubo
fubo

Reputation: 46005

Approach with ElementOrDefault()

https://dotnetfiddle.net/fxVo6T

int?[] items = { 1, 3, 5, 7, 9, 13  };
for (int i = 0; i < items.Length; i++)
{
    int? previous = items.ElementAtOrDefault(i - 1);
    int? current = items.ElementAtOrDefault(i);
    int? next = items.ElementAtOrDefault(i + 1);
}

Upvotes: 2

Deepak Mishra
Deepak Mishra

Reputation: 3193

This can be done using LinkedList<T>

List<int> intList = new List<int> { 1, 3, 5, 7, 9, 13 };

LinkedList<int> intLinkedList = new LinkedList<int>(intList);

Console.WriteLine("Next Value to 9 "+intLinkedList.Find(9).Next.Value);

Console.WriteLine("Next Value to 9 " +intLinkedList.Find(9).Previous.Value);

//Consider using dictionary for frequent use
var intDictionary = intLinkedList.ToDictionary(i => i, i => intLinkedList.Find(i));    

Console.WriteLine("Next Value to 9 " + intDictionary[9].Next.Value);

Console.WriteLine("Next Value to 9 " + intDictionary[9].Previous.Value);

Console.Read();

Upvotes: 3

BJ Patel
BJ Patel

Reputation: 6278

Following may be helpful

 int NextValue = 0;
 int PreviousValue =0;
 int index = lstOfNo.FindIndex(nd =>nd.Id == 9);

 var Next = lstOfNo.ElementAtOrDefault(index + 1);
 var Previous = lstOfNo.ElementAtOrDefault(index - 1);

 if (Next != null)
     NextValue = Next;


if (Previous != null)
   PreviousValue = Previous;

Upvotes: 7

Adil
Adil

Reputation: 148180

You can use indexer to get element at desired index. Adding one to index will get you next and subtracting one from index will give you previous element.

int index = 4; 
int prev = list[index-1];
int next = list[index+1];

You will have to check if next and previous index exists other wise you will get IndexOutOfRangeException exception. As List is zero based index so first element will have index 0 and second will have 1 and so on.

if(index - 1 > -1)
   prev = list[index-1];
if(index + 1 < list.Length)
   next = list[index+1];

Upvotes: 40

user2160375
user2160375

Reputation:

var index = list.IndexOf(9);
if (index == -1) 
{
   return; // or exception - whater, no element found.
}

int? nextItem = null; //null means that there is no next element.
if (index < list.Count - 1) 
{
   nextItem = list[index + 1];
}

int? prevItem = null;
if (index > 0) 
{
   prevItem = list[index - 1];
}

Upvotes: 3

xecollons
xecollons

Reputation: 608

        List<int> listInts = new List<int>();
        listInts.AddRange(new int[] { 1, 3, 5, 7, 9, 13 });
        int index = listInts.IndexOf(3); //The index here would be "1"
        index++; //Check first if the index is in the length
        int element = listInts[index]; //element = 5

Upvotes: 8

Selman Gen&#231;
Selman Gen&#231;

Reputation: 101711

int index = list.IndexOf(9); // find the index of the given number

// find the index of next and the previous number
// by taking into account that 
// the given number might be the first or the last number in the list
int prev = index > 0 ? index - 1 : -1;

int next = index < list.Count - 1 ? index + 1 : -1;

int nextItem, prevItem;

// if indexes are valid then get the items using indexer 
// otherwise set them to a temporary value, 
// you can also use Nullable<int> instead
nextItem = prev != -1 ? list[prev] : 0;
prevItem = next != -1 ? list[next] : 0;

Upvotes: 4

Related Questions