I'm looking for help finding an extension method for TakeLast that someone has written that can work for older versions of .Net Framework like 4.6 and higher. The default TakeLast method only works with my project for .Net 5 and .Net 6 but I'm trying to allow my program to be run on .Net Framework and the only thing I haven't been able to figure out is how to workaround the lack of TakeLast
Asked
Active
Viewed 396 times
-3
-
1Have you seen [this](https://stackoverflow.com/q/3453274/1911064) related question? – Axel Kemper Jan 09 '22 at 20:07
-
[MoreLinq.TakeLast](https://morelinq.github.io/2.4/ref/api/html/M_MoreLinq_MoreEnumerable_TakeLast__1.htm) – Charlieface Jan 09 '22 at 20:20
-
@AxelKemper No I didn't see that question before so thank you – DarthVegan Jan 09 '22 at 20:20
-
Take care how you word your questions - how this is written is essentially "find me a library that .." and is off topic – Caius Jard Jan 09 '22 at 20:34
1 Answers
1
You can implement your own extension method, something like this:
public static partial class EnumearbleExtensions {
public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int count) {
if (null == source)
throw new ArgumentNullException(nameof(source));
if (count < 0)
throw new ArgumentOutOfRangeException(nameof(count));
if (0 == count)
yield break;
// Optimization (see JonasH's comment)
if (source is ICollection<T>) {
foreach (T item in source.Skip(((ICollection<T>)source).Count - count))
yield return item;
yield break;
}
if (source is IReadOnlyCollection<T>) {
foreach (T item in source.Skip(((IReadOnlyCollection<T>)source).Count - count))
yield return item;
yield break;
}
// General case, we have to enumerate source
Queue<T> result = new Queue<T>();
foreach (T item in source) {
if (result.Count == count)
result.Dequeue();
result.Enqueue(item);
}
foreach (T item in result)
yield return result.Dequeue();
}
}

Dmitry Bychenko
- 180,369
- 20
- 160
- 215
-
1Consider also adding a check if the source implements `ICollection`/`IReadOnlyCollection` and if so just use `.Skip(...)` – JonasH Jan 09 '22 at 20:18
-
-
@JonasH: thank you! Testing for `ICollection`/`IReadOnlyCollection` case is a valuable optimization – Dmitry Bychenko Jan 09 '22 at 20:32
-
@DmitryBychenko This new version has an error if the item is an ICollection but the requested amount is higher than the source count and returns nothing except the expected action would be returning the source as is. For example if the source list has one item and it was asked to take the last 2 items, the result would be to return nothing – DarthVegan Jan 27 '22 at 20:51
-
@DmitryBychenko This is the code I used to fix your version in case you are interested: foreach (T item in source.Skip(Math.Max(0, ((ICollection
)source).Count - count))) yield return item; – DarthVegan Jan 27 '22 at 21:07 -
@DarthVegan: Thank you! My bad, it should have been `count` subtracted: `((ICollection
)source).Count - count`: if we `Skip` negative value (say, `Skip(-10)`) it equals `Skip` nothing: `Skip(0)` – Dmitry Bychenko Jan 27 '22 at 21:07 -
@DmitryBychenko Oh for some reason I thought you would get an error if you tried to skip a negative number so I set my version to a minimum of 0 but either way your code is great so thanks – DarthVegan Jan 27 '22 at 21:11