Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

I want to implement paging on a list of data. The list has some fake items in itself as flag items for doing some specific work on the data. A simplified version of what I have done is as below:

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

But my problem with this way is that the fake items will be counted in the Skip and Take methods of the Linq.

I want to know if it is possible to ignore those fake items in the Skip method then apply Skip on the list, including fake items by some changes in the Take method for example or something similar.

Edit: The first list is ordered before doing paging and those fake items are in ordered places also. You should know the order of the list is important for me.

like image 654
Milad Rashidi Avatar asked Nov 21 '17 13:11

Milad Rashidi


People also ask

What is skip in LINQ?

The Take operator is used to return a given number of elements from an array and the Skip operator skips over a specified number of elements from an array. Skip, skips elements up to a specified position starting from the first element in a sequence.

What is the difference between Skip () and SkipWhile () extension method?

Skip specifies a number of items to skip. SkipWhile allows you to supply a predicate function to determine how many to skip.

What is the use of skip in C#?

Use the Skip() method in C# to skip number of elements in an array.


2 Answers

To be honest I don't like what you're doing. I'd consider modelling your data better in future. However, here's a couple of extension methods that'll get the job done...

(I've essentially modified the original implementations of Skip and Take from https://github.com/Microsoft/referencesource/blob/master/System.Core/System/Linq/Enumerable.cs)

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

Usage...

pagedData = list.SkipAndInclude((page - 1) * pageSize, x => x.Fake).TakeAndInclude(pageSize, x => x.Fake);
like image 60
James Law Avatar answered Sep 22 '22 23:09

James Law


How about iterating over the list manually to find the index of fake items, then adding them in later. Something like this:

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);
}
like image 24
ste-fu Avatar answered Sep 21 '22 23:09

ste-fu