1

I have list as follows

static List<MessageDetail> CurrentMessage = new List<MessageDetail>();

Dynamically, values assigned to this list for example:

CurrentMessage.Add(new MessageDetail { UserName = 123,GroupName = somegrp, Message = somemsg });

Here, I want to take last 5 or so records.

// this returns first 5 result, dont want to user orderby clause either
CurrentMessagesForGroup = CurrentMessage
                          .Where(c => c.GroupName == groupName)
                          .Take(5).ToList();

Is there a way to implement TakeLast() attribute? Or any kind of help will be appreciated. Thanks for your time.

Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
Suhail Mumtaz Awan
  • 3,295
  • 8
  • 43
  • 77
  • 1
    If you don't want to use order by then how do you fix the last five entries?? By entry time or something else? – Rashik Hasnat Jul 26 '16 at 10:58
  • 1
    Possible duplicate of [Using Linq to get the last N elements of a collection?](http://stackoverflow.com/questions/3453274/using-linq-to-get-the-last-n-elements-of-a-collection) – Jaimie Knox Jul 26 '16 at 18:08

7 Answers7

4

Use skip:

CurrentMessagesForGroup = CurrentMessage
                    .Where(c => c.GroupName == groupName).Skip(Math.Max(0, CurrentMessage.Count() - 5)).ToList();

EDIT: I also find this that I think it is more easier to use (MoreLinq):

using MoreLinq;

var CurrentMessagesForGroup2 = CurrentMessage.TakeLast(5);
Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
3

Use an OrderBy (ASC or DESC) to get the records lined up correctly for your Take operation.

Ascending:

CurrentMessagesForGroup = CurrentMessage
                        .Where(c => c.GroupName == groupName)
                        .OrderBy(c => c.GroupName)
                        .Take(5)
                        .ToList();

or Descending:

CurrentMessagesForGroup = CurrentMessage
                        .Where(c => c.GroupName == groupName)
                        .OrderByDescending(c => c.GroupName)
                        .Take(5)
                        .ToList();
Murray Foxcroft
  • 12,785
  • 7
  • 58
  • 86
  • Thanks for answer but as i already stated i dont want to use orderby clause . – Suhail Mumtaz Awan Jul 26 '16 at 11:02
  • 1
    I missed that in the comment. If you just want the last 5 added, then go with S.Akbari's answer, covered here as well http://stackoverflow.com/questions/3453274/using-linq-to-get-the-last-n-elements-of-a-collection – Murray Foxcroft Jul 26 '16 at 11:08
2

If anyone using DotNet Core 2 or above or DotNet Standard 2.1 or above then you can use Linq's built in .TakeLast()

Reference: Microsoft Documentation here

Shuvo Amin
  • 631
  • 8
  • 14
1

You could use Reverse(), which is slightly perverse.

CurrentMessagesForGroup = CurrentMessage
                    .Where(c => c.GroupName == groupName)
                    .Reverse()
                    .Take(5).ToList();
J. Steen
  • 15,470
  • 15
  • 56
  • 63
1

I use an extension method for this.

public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int numElements)
{
    return source.Skip(Math.Max(0, source.Count() - numElements));
}

And to use it:

CurrentMessagesForGroup = CurrentMessage.Where(c => c.GroupName == groupName).TakeLast(5).ToList();

Edit: Credit to Using Linq to get the last N elements of a collection?

Community
  • 1
  • 1
Jaimie Knox
  • 167
  • 2
  • 4
  • 13
1

I like this implementation, it uses a circular buffer.

public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> input, int n)
{
    if (n == 0)
        yield break;

    int tail = 0;
    int head = 0;
    int count = 0;

    T[] buffer = new T[n];

    foreach (T item in input)
    {
        buffer[tail] = item;

        tail = (tail + 1) % n;

        if (count < n)
            count++;
        else
            head = (head + 1) % n;
    }

    for (int i = 0; i < count; i++)
        yield return buffer[(head + i) % n];
}
0

If the MessageDetails class has numeric Id or Created date time we can use

var lastRecords= CurrentMessage.OrderByDescending(i=>i.Id).Where(p=>p.GroupName==groupName).Take(5).ToList(); 
Syam Kumar
  • 343
  • 5
  • 16