LINQ列表中的下一个项目

22

看看我在这里提出的问题,现在我想返回满足条件的下一个推荐对象(之后)。

比如说我找到了10个中的第6个项目,我希望查询返回第7个项目。

还是有更好的方法吗?

7个回答

53

这是目前我最好的方法:

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

早先的答案使用了Skip(1).Take(1),这个方法是可行的,但返回结果是一个包含一个结果的列表。在我的情况下(也许是OP的情况),我们要找的是实际的项。所以我的代码会跳过直到我们要找的那一项(使用 Where 方法会返回子集,因此我们将无法访问下一项),然后再跳过一项并获取该项。


注意:此答案在微软虚拟学院课程“解密LINQ”-第6部分中提到。 - John M
这应该是答案。 - John Livermore

17

试试这个


下一个项目

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

我认为SQL Server中没有实现“Reverse”。 - Luke Vo
这是LINQ和Reverse的链接:http://msdn.microsoft.com/zh-cn/library/bb358497(v=vs.110).aspx - Abdul Saboor
是的,这是LINQ API,但如果它是LINQ to SQL(Server),它会抛出错误,因为在SQL中没有等价物。 - Luke Vo
2
是的!你说得对,如果使用LINQ to SQL会抛出一个错误。但我认为我们现在不是在谈论LINQ to SQL。让我编辑我的答案,这样大家就会知道了。 - Abdul Saboor
完美地适用于 ICollection<T>。我将其改编为仅获取一个结果,使用对象:list.SkipWhile(x => !x.Equals(myObject)).Skip(1).Take(1).SingleOrDefault() - Emy Blacksmith

16

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

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

一旦你获得了索引,你就可以获取下一个或上一个项目,或者任何你想要的。


7

这样的东西怎么样:

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

1

这个应该可以解决问题。我还没有专门为它构建测试。

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。


1
如果您确定:
  • 该项在列表中是唯一的
  • 该项来自同一列表
  • 存在下一个项目

您可以通过以下方式获取下一个项目

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

如果你不确定是否存在下一个项目,可以使用try+catch或者:

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

0

项目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);

我不认为这会完全奏效。在OP的情况下,原始数据似乎只会返回一个结果,而他们想得到原始列表中的下一个结果。 - Adriaan Stander
@spoulson,没错。我想找到匹配的项目,然后返回列表中的下一个项目。 - griegs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接