【问题标题】:LINQ Next Item in ListLINQ 列表中的下一项
【发布时间】:2010-04-21 03:59:54
【问题描述】:

看看我的问题HERE,我现在想返回下一个recommendation对象(在匹配条件的对象之后)。

假设我在 10 项中找到了第 6 项,我希望查询返回第 7 项。

或者有没有更好的方法?

【问题讨论】:

    标签: linq


    【解决方案1】:

    这是我目前最好的方法:

    MyList.SkipWhile(item => item.Name != "someName").Skip(1).FirstOrDefault()
    

    较早的答案使用Skip(1).Take(1),它有效,但返回一个结果列表。在我的情况下(也许是 OP 的情况),我们正在寻找实际的项目。所以我的代码会跳过,直到它到达我们正在寻找的那个(一个 Where 将返回一个子集,因此我们无法访问下一个项目)然后再跳过一个,然后获取该项目。

    【讨论】:

    • 注意:这个答案在微软虚拟学院课程'De-Mystifying LINQ' - Part 6中提到
    • 这应该是答案。
    【解决方案2】:

    试试这个


    下一项

    MyList.SkipWhile(x => x != value).Skip(1).FirstOrDefault();
    

    上一个项目注意:Reverse() 不适用于 LINQ to SQL

     var MyList2 = MyList.ToList();
     MyList2.Reverse();
     MyList2.SkipWhile(x => x != value).Skip(1).FirstOrDefault();
    

    【讨论】:

    • 我认为Reverse在SQL Server中没有实现。
    • 是的,是LINQ API,但是如果是LINQ to SQL (Server),会报错,因为SQL没有等价性。
    • 是的!你是对的,它会在 LINQ to SQL 的情况下引发错误。但我不认为我们在这里谈论的是 LINQ to SQL。让我编辑我的答案,以便人们知道它。
    • ICollection<T> 完美配合。我对此进行了调整,只得到一个结果,对象为:list.SkipWhile(x => !x.Equals(myObject)).Skip(1).Take(1).SingleOrDefault()
    【解决方案3】:

    如果你确定:

    • 该项目在列表中是唯一的
    • 项目来自同一个列表
    • 还有下一项

    您可以通过这种方式获得下一个项目

    myList[myList.IndexOf(item) + 1];
    // or
    myList.ElementAt(myList.IndexOf(item) + 1);
    

    如果您不确定是否有下一项,您可以使用try + catch 或:

    myList.ElementAtOrDefault(myList.IndexOf(item) + 1);
    

    【讨论】:

      【解决方案4】:

      这样的事情怎么样:

      public static class Extension
      {
          public static T Next<T>(this IEnumerable<T> source, Func<T, bool> predicate)
          {
              bool flag = false;
      
              using (var enumerator = source.GetEnumerator())
              {
                  while (enumerator.MoveNext())
                  {
                      if (flag) return enumerator.Current;
      
                      if(predicate(enumerator.Current))
                      {
                          flag = true;
                      }
                  }
              }
              return default(T);
          }
      }
      

      然后你可以像在 Where 中那样调用它

      Products.Next(x => x.Whatever);
      

      【讨论】:

        【解决方案5】:

        由于您有一个List&lt;T&gt; 对象,您可以使用它的FindIndex 方法而不是Where 来获取第一个匹配项的索引而不是该项本身:

        int index = recommendations.FindIndex(rp =>
                                                    rp.Products.Any(p => p.Product.Code == "A") 
                                                 && rp.Products.Any(p => p.Product.Code == "B")
                                              );
        

        一旦你有了索引,你就可以得到下一个或上一个或任何你想要的。

        【讨论】:

          【解决方案6】:

          应该这样做。我还没有专门为它构建测试。

          var nextProducts = from item1 in recommendations.Select((rec, idx) => new { Rec = rec, Index = idx })
                              join item2 in recommendations.Select((rec, idx) => new { Rec = rec, Index = idx })
                              on item1.Index equals item2.Index - 1
                              where item1.Rec.Products.Any(p => p.Code == "A")
                              && item1.Rec.Products.Any(p => p.Code == "B")
                              select item2.Rec;
          

          如果你需要两条记录,选择语句可以是

          select new { MatchingItem = item1.Rec, NextItem = item2.Rec };
          

          但是您必须进行分组以说明匹配项是列表中的最后一项(在这种情况下不会有下一项)。

          var nextProducts = from item1 in recommendations.Select((rec, idx) => new { Rec = rec, Index = idx })
                              join item2 in recommendations.Select((rec, idx) => new { Rec = rec, Index = idx })
                              on item1.Index equals item2.Index - 1
                              into groupjoin
                              from i2 in groupjoin.DefaultIfEmpty ()
                              where item1.Rec.Products.Any(p => p.Code == "A")
                              && item1.Rec.Products.Any(p => p.Code == "B")
                              select new { MatchingItem = item1.Rec, NextItem = i2 == null ? null : i2.Rec };
          

          测试的代码类似于字符串列表。

          List<string> list = new List<string>() { "a", "b", "c", "a", "d", "a", "e" };
          
          var query = from item1 in list.Select((s, idx) => new { Item = s, Index = idx })
                      join item2 in list.Select((s, idx) => new { Item = s, Index = idx })
                      on item1.Index equals item2.Index - 1
                      where item1.Item == "a"
                      select item2.Item;
          

          返回 b、d 和 e。

          【讨论】:

            【解决方案7】:

            第 7 项是否与您的 Where 子句匹配?如果是这样,请使用Skip()Take() 扩展方法:

            var myProducts =
               from rp in recommendations
               where
                  cp.Products.Any(p => p.Product.Code == "A") &&
                  cp.Products.Any(p => p.Product.Code == "B")
               select rp;
            
            var nextProduct = myProducts.Skip(1).Take(1);
            

            【讨论】:

            • 我认为这不会完全有效。在 OPs 的情况下,原来的似乎只会返回 1 个结果,他们想要 ORIGINAL 列表中的下一个。
            • @spoulson,没错。我想找到匹配的项目,然后返回列表中的下一个项目。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-05-18
            • 2022-01-21
            • 1970-01-01
            • 2017-02-04
            • 2016-09-25
            • 2012-07-10
            相关资源
            最近更新 更多