是否可以使用 LINQ 的 Skip 方法忽略列表项,然后在列表上应用 skip 而不会丢失该项目?

Posted

技术标签:

【中文标题】是否可以使用 LINQ 的 Skip 方法忽略列表项,然后在列表上应用 skip 而不会丢失该项目?【英文标题】:Is it possible to ignore a list item using the Skip method of the LINQ then apply skip on the list without losing that item? 【发布时间】:2018-05-05 00:24:53 【问题描述】:

我想在数据列表上实现分页。该列表本身有一些虚假项目作为标记项目,用于对数据进行某些特定工作。我所做的简化版本如下:

List<Model> list = _myServiceContract.MyServiceMethod(MySearchModel);
pagedData = list.Skip((page - 1) * pageSize).Take(pageSize);

但我对这种方式的问题是,假货将计入 LinqSkipTake 方法中。

我想知道是否可以忽略Skip 方法中的那些假项目,然后在列表中应用Skip,包括通过Take 方法或类似方法中的一些更改而产生的假项目。

编辑:第一个列表是在进行分页之前排序的,那些假项目也在有序的地方。你应该知道列表的顺序对我很重要。

【问题讨论】:

您可以在Skip 前面加上Where 以首先过滤掉“假”物品。 没有@juharr。条件会从结果中丢失假数据 你能TakeWhile(fake).Skip((page - 1) * pageSize).Take(pageSize)吗?一组示例数据会很有帮助,我不太确定从您的描述中会是什么样子。 类似.SkipWhile(x =&gt; (x.IsFake ? toSkip : toSkip--) &gt; 0).TakeWhile(x =&gt; (x.IsFake ? toTake : toTake--) &gt; 0)。您只需预先计算 toSkiptoTake 并允许查询在您检查项目是否为假时改变这些值。 【参考方案1】:

说实话,我不喜欢你的所作所为。我会考虑将来更好地对您的数据进行建模。但是,这里有几个扩展方法可以完成工作......

(我从https://github.com/Microsoft/referencesource/blob/master/System.Core/System/Linq/Enumerable.cs 基本上修改了SkipTake 的原始实现)

public static IEnumerable<TSource> SkipAndInclude<TSource>(this IEnumerable<TSource> source, int count, Func<TSource, bool> predicate)

    if (source == null) throw new ArgumentNullException(nameof(source));
    if (predicate == null) throw new ArgumentNullException(nameof(predicate));

    using (IEnumerator<TSource> e = source.GetEnumerator())
    
        while (count > 0 && e.MoveNext())
        
            if (!predicate(e.Current)) count--;
        
        if (count <= 0)
        
            while (e.MoveNext()) yield return e.Current;
        
    


public static IEnumerable<TSource> TakeAndInclude<TSource>(this IEnumerable<TSource> source, int count, Func<TSource, bool> predicate)

    if (source == null) throw new ArgumentNullException(nameof(source));
    if (predicate == null) throw new ArgumentNullException(nameof(predicate));

    if (count > 0)
    
        foreach (TSource element in source)
        
            yield return element;
            if (!predicate(element)) count--;
            if (count == 0) break;
        
    

用法...

pagedData = list.SkipAndInclude((page - 1) * pageSize, x => x.Fake).TakeAndInclude(pageSize, x => x.Fake);

【讨论】:

【参考方案2】:

如何手动遍历列表以查找虚假项目的索引,然后稍后添加它们。像这样的:

var fakeItems = new Dictionary<int, Model>();
var unpaged = MyService.MyServiceMethod(MySearchModel);

for (var i = 0; i < unpaged.Count; i++)

    if (unpaged[i].IsFake)
        fakeItems.Add(i, unpaged[i]);


var paged = unpaged.Where(x => !x.IsFake)
    .Skip((page - 1) * pageSize)
    .Take(pageSize);

foreach (var item in fakeItems)

    if((pageSize * (page - 1)) <= item.Key && item.Key < (pageSize * page))
        paged.Insert(item.Key, item.Value);

【讨论】:

【参考方案3】:

只需使用 where 来忽略这些项目,如下所示:

List<Model> list = MyService.MyServiceMethod(MySearchModel);
pagedData = list.Where(x => !x.Fake).Skip((page - 1) * pageSize).Take(pageSize).ToList();

不要忘记订购您的物品。否则在分页(skip & take)时可能会出现问题。

【讨论】:

我之前试过这个解决方案。它将从结果中丢失假货。 我不完全明白你想在哪里拥有这些物品以及每页应该有多少假货。在我看来,也许你正试图用一个 List 做一些你应该用两种不同的方法做的事情?请向我提供有关您的要求的更多信息,以便我想出更好的解决方案。

以上是关于是否可以使用 LINQ 的 Skip 方法忽略列表项,然后在列表上应用 skip 而不会丢失该项目?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Linq Skip Take 进行传统 SQL 查询,而不是使用 RowNum

LinQ中Skip()方法和Take()方法的使用

Linq中Take与Skip的使用

PagedList 使用 LINQ Skip and Take,但使用 Count of results 显示分页

分页错误:仅 LINQ to Entities 中的排序输入支持“跳过”方法。方法 'OrderBy' 必须在方法 'Skip' 之前调用

LINQ 查询添加 orderby 使 Skip 和 Take 不起作用 Linqpad