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()));
}
Drop the last item with LINQ
For .NET Core 2+ and .NET Standard 2.1 (planned), you can use .SkipLast(1)
.
For other platforms, you could write your own LINQ query operator (that is, an extension method on IEnumerable<T>
), for example:
static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
using (var e = source.GetEnumerator())
{
if (e.MoveNext())
{
for (var value = e.Current; e.MoveNext(); value = e.Current)
{
yield return value;
}
}
}
}
Unlike other approaches such as xs.Take(xs.Count() - 1)
, the above will process a sequence only once.
Don't take last record in linq C#
What about this:
static public IEnumerable<T> SkipLast<T>(this IEnumerable<T> data, int count)
{
if (data == null || count < 0) yield break;
Queue<T> queue = new Queue<T>(data.Take(count));
foreach (T item in data.Skip(count))
{
queue.Enqueue(item);
yield return queue.Dequeue();
}
}
Update
With help from some reviews an optimized version building on the same idea could be:
static public IEnumerable<T> SkipLast<T>(this IEnumerable<T> data, int count)
{
if (data == null) throw new ArgumentNullException(nameof(data));
if (count <= 0) return data;
if (data is ICollection<T> collection)
return collection.Take(collection.Count - count);
IEnumerable<T> Skipper()
{
using (var enumer = data.GetEnumerator())
{
T[] queue = new T[count];
int index = 0;
while (index < count && enumer.MoveNext())
queue[index++] = enumer.Current;
index = -1;
while (enumer.MoveNext())
{
index = (index + 1) % count;
yield return queue[index];
queue[index] = enumer.Current;
}
}
}
return Skipper();
}
how to take all array elements except last element in C#
var remStrings = queries.Take(queries.Length - 1);
No need to Reverse and Skip. Just take one less element than there are in the array.
If you really wanted the elements in the reverse order, you could tack on a .Reverse()
to the end.
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 skip last 2 records and get all other records with linq?
In this case: Take(8)
With Take
and Skip
you can get any range you want.
E.G:
var query = context.Test.OrderByDescending(t=>t.Id);
var allButTheLastTwoElements = query.Take(query.Count() - 2);
Safest way:
var query = context.Test.OrderByDescending(t=>t.Id).ToList();
var allButTheLastTwoElements = query.Take(Math.Max(0,query.Count() - 2));
Or you could just do it the other way around (depending on your requirements)
var query = context.Test.OrderByAscending(t=>t.Id).Skip(2);
How to get all elements except the n'th element in a List using Linq
Sure, using the overload of Where
that takes an index parameter:
var allBut3 = chars.Where((c, i) => i != 2); // use 2 since Where() uses 0-based indexing
Take all items except the last ones that satisfy condition?
There is no standard efficient LINQ solution. I would go with a custom extension "LINQ like" method like this:
public static class EnumerableExtensions
{
public static IEnumerable<T> SkipLastWhile<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
var skipBuffer = new List<T>();
foreach (var item in source)
{
if (predicate(item))
skipBuffer.Add(item);
else
{
if (skipBuffer.Count > 0)
{
foreach (var skipped in skipBuffer)
yield return skipped;
skipBuffer.Clear();
}
yield return item;
}
}
}
}
It requires additional space for buffering the longest item sequence satisfying the skip predicate while the LINQ Reverse
method has to buffer the whole input sequence.
The usage will be:
var result = input.SkipLastWhile(e => !e.Any());
Extend a list using last element to match longer list in LINQ zip
Staying in the .Net/C# world:
You could use something like:
var almostInfinite = items.Concat(Enumerable.Repeat(items.Last(), Int32.MaxValue));
but it will not yield a really infinite sequence.
Writting your own Extend
method isn't hard, either:
IEnumerable<T> Extend<T>(IEnumerable<T> source)
{
// error checking omitted
var e = source.GetEnumerator();
T last = default(T);
while(e.MoveNext())
yield return last = e.Current;
while(true)
yield return last;
}
You could also create another version of Zip
. Take a look at morelinq's Zip
, which handles source sequences of different sizes.
Sort List except one entry with LINQ, to be at the last
You can use either .Concat()
to add the string that you desire at the end or use .OrderBy()
to place your string at the end while leaving all others in the front and use .ThenBy()
afterwards to sort the items. .ThenBy()
will apply when you the previous orderings provide groups of items that are considered equal.
var list = new List<string> { "z", "u", "last", "b", "a" };
var result = list
.OrderBy(item => item == "last" ? 1 : 0)
.ThenBy(item => item);
Or in place sort
var list = new List<string> { "z", "u", "last", "b", "a" };
list.Sort((left, right) => left == "last" ? 1 : right == "last" ? -1 : string.Compare(left, right));
Using .Concat()
var list = new List<string> { "z", "u", "last", "b", "a" };
var result = list
.Where(item => item != "last")
.OrderBy(item => item)
.Concat(Enumerable.Repeat("last", 1));
Related Topics
"Padding Is Invalid and Cannot Be Removed" Using Aesmanaged
Multiple Controller Types with Same Route Prefix ASP.NET Web API
The Remote Server Returned an Unexpected Response: (413) Request Entity Too Large
Print Fixeddocument/Xps to PDF Without Showing File Save Dialog
C# Httpwebrequest the Underlying Connection Was Closed: an Unexpected Error Occurred on a Send
How to Segment the Elements Iterated Over in a Foreach Loop
Exclude a Field/Property from the Database with Entity Framework 4 & Code-First
Image.Fromstream() Method Returns Invalid Argument Exception
Using Extension Methods in .Net 2.0
Set Dllimport Attribute Dynamically
How to Format 07/03/2012 to March 7Th,2012 in C#
Are Timers and Loops in .Net Accurate
Passing Parameters to Xslt Stylesheet via .Net
Wpf: the Name Does Not Exist in the Namespace
How to Draw a Rounded Rectangle in C#
Child Actions Are Not Allowed to Perform Redirect Actions, After Setting the Site on Https
Formatting a C# String with Identical Spacing in Between Values