【问题标题】:Get previous/next item of a given item in a List<>获取 List<> 中给定项目的上一个/下一个项目
【发布时间】:2014-07-17 09:33:07
【问题描述】:

说我有这个列表:1、3、5、7、9、13

例如,给定值为:9,上一项为 7,下一项为 13

如何使用 C# 实现这一点?

【问题讨论】:

  • 获取给定项目的索引。加 1 移动下一个,减一移动上一个。确保检查边界。
  • 索引为 +/- 1.... 你试过什么?
  • 什么样的列表?使用(双重)链表非常容易,例如 LinkedList&lt;T&gt; 类。
  • 为什么是反对票?我问是因为我不知道如何实现这一点。
  • @hoangnnm - 如果您将鼠标悬停在反对票图标上,它会显示“这个问题没有显示任何研究工作”(我没有反对票)

标签: c# list


【解决方案1】:

您可以使用 indexer 来获取所需索引处的元素。将一个添加到索引将得到你 next 并且从索引中减去一个将得到你 previous 元素。

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

您必须检查下一个和上一个索引是否存在,否则您将得到IndexOutOfRangeException 异常。由于 List 是从零开始的索引,因此第一个元素的索引为 0,第二个元素的索引为 1,依此类推。

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

【讨论】:

    【解决方案2】:

    在一行中使用 LINQ 并进行循环搜索:

    下一个

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

    以前的

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

    这是一个工作示例(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);
    

    【讨论】:

    • 我必须在已知元素之前的两个位置获取一个元素,最后用.Reverse() 反转列表,然后使用.Skip(2) 的第一种方法
    【解决方案3】:

    我通过继承 .Net 列表实现了这一点

    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]; }
            }
        }
    

    使用它变得非常容易

     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");
    

    【讨论】:

    • 拥有一个修改对象内部状态的属性的获取器似乎是非常糟糕的做法(MoveNextMovePrevious)。更好地使它们发挥作用。还有可以指向无效索引的_currentIndex 似乎很奇怪。最好使用 setter 来更正索引(而不是让 getter 做同样的工作)。但我仍然喜欢这种方法!
    • 我同意@JackMiller 的上述观点,但我确实给了答案+1。用于解决您的需求的包装器类是一种优雅的方法,并使使用包装器的代码更易于阅读。 LINQ 在很多事情上都很糟糕……但是当事情变得复杂时,它可能很难阅读/理解。
    • 把这个答案和@Melad的答案结合起来,你可以得到一个完整的两个方向循环列表,太棒了!
    【解决方案4】:
            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
    

    【讨论】:

      【解决方案5】:

      以下可能会有所帮助

       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;
      

      【讨论】:

        【解决方案6】:

        此外,如果您想要具有循环逻辑的紧凑解决方案而不创建新列表,您可以使用以下代码:

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

        https://dotnetfiddle.net/PkP2Jy

        【讨论】:

          【解决方案7】:
          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;
          

          【讨论】:

          • 这可能会令人困惑。如果列表的元素是0 怎么办?然后我们无法确定列表中是否没有 next / prev 元素,或者只是列表中的元素。
          • @pwas 是的,我想使用 Nullable 会更好
          【解决方案8】:
          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];
          }
          

          【讨论】:

            【解决方案9】:

            使用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);
            }
            

            【讨论】:

            • 嘿!它看起来像上帝的爱一样简单明了。谢谢大哥!
            【解决方案10】:

            这可以使用LinkedList&lt;T&gt; 来完成

            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();
            

            【讨论】:

              【解决方案11】:

              要使其成为一种循环列表,请尝试以下操作:

              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]; }
                  }
              }
              

              【讨论】:

                【解决方案12】:

                这是结合@Thunder@Melad 得到的完整的圆形列表答案:

                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

                【讨论】:

                  猜你喜欢
                  • 2021-04-26
                  • 1970-01-01
                  • 2023-03-22
                  • 2011-04-26
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-08-05
                  • 1970-01-01
                  相关资源
                  最近更新 更多