Using Linq to get the last N elements of a collection?
collection.Skip(Math.Max(0, collection.Count() - N));
This approach preserves item order without a dependency on any sorting, and has broad compatibility across several LINQ providers.
It is important to take care not to call Skip
with a negative number. Some providers, such as the Entity Framework, will produce an ArgumentException when presented with a negative argument. The call to Math.Max
avoids this neatly.
The class below has all of the essentials for extension methods, which are: a static class, a static method, and use of the this
keyword.
public static class MiscExtensions
{
// Ex: collection.TakeLast(5);
public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int N)
{
return source.Skip(Math.Max(0, source.Count() - N));
}
}
A brief note on performance:
Because the call to Count()
can cause enumeration of certain data structures, this approach has the risk of causing two passes over the data. This isn't really a problem with most enumerables; in fact, optimizations exist already for Lists, Arrays, and even EF queries to evaluate the Count()
operation in O(1) time.
If, however, you must use a forward-only enumerable and would like to avoid making two passes, consider a one-pass algorithm like Lasse V. Karlsen or Mark Byers describe. Both of these approaches use a temporary buffer to hold items while enumerating, which are yielded once the end of the collection is found.
How to take last records from list
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);
How to take all but the last element in a sequence using LINQ?
I don't know a Linq solution - But you can easily code the algorithm by yourself using generators (yield return).
public static IEnumerable<T> TakeAllButLast<T>(this IEnumerable<T> source) {
var it = source.GetEnumerator();
bool hasRemainingItems = false;
bool isFirst = true;
T item = default(T);
do {
hasRemainingItems = it.MoveNext();
if (hasRemainingItems) {
if (!isFirst) yield return item;
item = it.Current;
isFirst = false;
}
} while (hasRemainingItems);
}
static void Main(string[] args) {
var Seq = Enumerable.Range(1, 10);
Console.WriteLine(string.Join(", ", Seq.Select(x => x.ToString()).ToArray()));
Console.WriteLine(string.Join(", ", Seq.TakeAllButLast().Select(x => x.ToString()).ToArray()));
}
Or as a generalized solution discarding the last n items (using a queue like suggested in the comments):
public static IEnumerable<T> SkipLastN<T>(this IEnumerable<T> source, int n) {
var it = source.GetEnumerator();
bool hasRemainingItems = false;
var cache = new Queue<T>(n + 1);
do {
if (hasRemainingItems = it.MoveNext()) {
cache.Enqueue(it.Current);
if (cache.Count > n)
yield return cache.Dequeue();
}
} while (hasRemainingItems);
}
static void Main(string[] args) {
var Seq = Enumerable.Range(1, 4);
Console.WriteLine(string.Join(", ", Seq.Select(x => x.ToString()).ToArray()));
Console.WriteLine(string.Join(", ", Seq.SkipLastN(3).Select(x => x.ToString()).ToArray()));
}
Get Last N Element From Entity by LINQ
Under assumption that _db.Table1 is queryable you can try following:
var id = _db.table1.Max(e => e.Id);
Get last element (based on names) in a list - LINQ C#
Why not ignore anonymous types and SelectMany
and just do:
modList.GroupBy(p => p.Name).Select(g => g.Last())
It's got nothing to do with anonymous types as per your title, but it does result in the sort of results you mention at the start of the question.
how to get specific collection from a collection with linq?
Short answer based on my understanding of this:
var forms = root.Data
.SelectMany(datum => datum.Evaluations)
.Select(evaluation => evaluation.Form)
.ToList();
Long answer with test
You don't specify class Form
, hence I tested with this minimum code:
using System.Collections.Generic;
namespace XUnitTestProject.StackOverflow
{
public class Root
{
public List<Datum> Data { get; set; }
}
public class Datum
{
public List<Evaluation> Evaluations { get; set; }
}
public class Form
{
public string Name { get; set; }
}
public class Evaluation
{
public Form Form { get; set; }
}
}
And a test class
using System.Collections.Generic;
using System.Linq;
using Xunit;
namespace XUnitTestProject.StackOverflow
{
public class LinqTests
{
[Fact]
public void Test()
{
var forms = CreateValidRoot().Data
.SelectMany(datum => datum.Evaluations)
.Select(evaluation => evaluation.Form)
.ToList();
Assert.Equal(2, forms.Count);
Assert.Equal("~form1~", forms[0].Name);
Assert.Equal("~form2~", forms[1].Name);
}
private static Root CreateValidRoot() => new()
{
Data = new List<Datum>
{
new()
{
Evaluations = new List<Evaluation>
{
new() {Form = new Form{Name = "~form1~"}}
}
},
new()
{
Evaluations = new List<Evaluation>
{
new() {Form = new Form{Name = "~form2~"}}
}
}
}
};
}
}
Using LINQ expression to get previous element from a collection
You could use TakeWhile
and LastOrDefault
:
var meeting = Meetings.TakeWhile(m => !m.Selected)
.LastOrDefault();
if (meeting != null)
{
// Use the meeting
}
else
{
// The first meeting was selected, or there are no meetings
}
TakeWhile
basically stops when it hits the first item that doesn't match the predicate - it's like a Where
that stops early, in other words.
You need to be careful with ordering though - you're pretty much assuming there's a bunch of unselected meetings, followed by selected ones.
Related Topics
Deserializing JSON When Sometimes Array and Sometimes Object
How to Select Distinct Rows in a Datatable and Store into an Array
.Net/C# - Convert Char[] to String
How to Set Session Timeout in Web.Config
Gradient Circles for Map Generator
Why Should I Prefer Single 'Await Task.Whenall' Over Multiple Awaits
How to Get a Property Value Based on the Name
A Field Initializer Cannot Reference the Non-Static Field, Method, or Property
How to Get Difference Between Two Dates in Year/Month/Week/Day
Typeloadexception Says 'No Implementation', But It Is Implemented
Getting the Http Referrer in ASP.NET
Casting a Variable Using a Type Variable
Concurrent Hashset<T> in .Net Framework
C# Is Rounding Down Divisions by Itself