From 0876f6512c11c992aaab782f7ff1d15f2f42bf9b Mon Sep 17 00:00:00 2001 From: Orace Date: Tue, 5 Nov 2019 15:11:31 +0100 Subject: [PATCH] - Add a test for SkipLast for ICollection input sequence - Add a custom implementation for SkipLast that avoid object creation for each item --- MoreLinq.Test/SkipLastTest.cs | 15 ++++++++++++++- MoreLinq/SkipLast.cs | 28 ++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/MoreLinq.Test/SkipLastTest.cs b/MoreLinq.Test/SkipLastTest.cs index 715f53be4..3985385a3 100644 --- a/MoreLinq.Test/SkipLastTest.cs +++ b/MoreLinq.Test/SkipLastTest.cs @@ -32,7 +32,7 @@ public void SkipLastWithCountLesserThanOne(int skip) } [Test] - public void SkipLast() + public void SkipLastEnumerable() { const int take = 100; const int skip = 20; @@ -44,6 +44,19 @@ public void SkipLast() Assert.That(expectations, Is.EqualTo(sequence.SkipLast(skip))); } + [Test] + public void SkipLastCollection() + { + const int take = 100; + const int skip = 20; + + var sequence = Enumerable.Range(1, take).ToArray(); + + var expectations = sequence.Take(take - skip); + + Assert.That(expectations, Is.EqualTo(sequence.SkipLast(skip))); + } + [TestCase(5)] [TestCase(6)] public void SkipLastWithSequenceShorterThanCount(int skip) diff --git a/MoreLinq/SkipLast.cs b/MoreLinq/SkipLast.cs index 6aebe4c3f..b564f77ae 100644 --- a/MoreLinq/SkipLast.cs +++ b/MoreLinq/SkipLast.cs @@ -40,12 +40,28 @@ public static IEnumerable SkipLast(this IEnumerable source, int count) if (count < 1) return source; - return - source.TryGetCollectionCount() is int collectionCount - ? source.Take(collectionCount - count) - : source.CountDown(count, (e, cd) => (Element: e, Countdown: cd )) - .TakeWhile(e => e.Countdown == null) - .Select(e => e.Element); + var collectionCount = source.TryGetCollectionCount(); + if (collectionCount.HasValue) + { + return source.Take(collectionCount.Value - count); + } + + return _(); IEnumerable _() + { + var queue = new Queue(count); + using var enumerator = source.GetEnumerator(); + + while (count-- > 0 && enumerator.MoveNext()) + { + queue.Enqueue(enumerator.Current); + } + + while (enumerator.MoveNext()) + { + yield return queue.Dequeue(); + queue.Enqueue(enumerator.Current); + } + } } } }