-
-
Save VisualMelon/1ab841a5b9204517675236e6645c537d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# depends on BenchmarkDotNet | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using BenchmarkDotNet.Attributes; | |
using BenchmarkDotNet.Running; | |
namespace SkipLastBenchmark | |
{ | |
public static class Exts | |
{ | |
static public IEnumerable<T> SkipLast1<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(); | |
} | |
} | |
static public IEnumerable<T> SkipLast2<T>(this IEnumerable<T> data, int count) | |
{ | |
if (data == null || count < 0) | |
yield break; | |
if (count == 0) | |
{ | |
foreach (T item in data) | |
yield return item; | |
} | |
else | |
{ | |
T[] queue = data.Take(count).ToArray(); | |
int index = 0; | |
foreach (T item in data.Skip(count)) | |
{ | |
index %= count; | |
yield return queue[index]; | |
queue[index] = item; | |
index++; | |
} | |
} | |
} | |
static public IEnumerable<T> SkipLast3<T>(this IEnumerable<T> source, int count) | |
{ | |
if (source == null) | |
throw new ArgumentNullException("Source Enumeration may not be null", nameof(source)); | |
if (count <= 0) | |
{ | |
foreach (T item in source) | |
yield return item; | |
} | |
else | |
{ | |
bool yielding = false; | |
T[] buffer = new T[count]; | |
int index = 0; | |
foreach (T item in source) | |
{ | |
if (index == count) | |
{ | |
index = 0; | |
yielding = true; | |
} | |
if (yielding) | |
yield return buffer[index]; | |
buffer[index] = item; | |
index++; | |
} | |
} | |
} | |
static public IEnumerable<T> SkipLast4<T>(this IEnumerable<T> source, int count) | |
{ | |
if (source == null) | |
throw new ArgumentNullException("Source Enumeration may not be null", nameof(source)); | |
if (count <= 0) | |
{ | |
foreach (T item in source) | |
yield return item; | |
} | |
else | |
{ | |
T[] buffer = new T[count]; | |
using (var e = source.GetEnumerator()) | |
{ | |
// initial filling of buffer | |
for (int i = 0; i < buffer.Length; i++) | |
{ | |
if (!e.MoveNext()) | |
yield break; | |
buffer[i] = e.Current; | |
} | |
int index = 0; | |
while (e.MoveNext()) | |
{ | |
yield return buffer[index]; | |
buffer[index] = e.Current; | |
index = (index + 1) % count; | |
} | |
} | |
} | |
} | |
} | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var summary = BenchmarkRunner.Run<Bench>(); | |
} | |
} | |
public class Bench | |
{ | |
public IEnumerable<int> Lengths => new int[] { 0, 100, 100000 }; | |
public IEnumerable<int> Counts => new int[] { 0, 10, 1000 }; | |
[ParamsSource(nameof(Lengths))] | |
public int Length { get; set; } | |
[ParamsSource(nameof(Counts))] | |
public int Count { get; set; } | |
public IEnumerable<int> Array { get; set; } | |
public IEnumerable<int> Range { get; set; } | |
public IEnumerable<int> Thing { get; set; } | |
[GlobalSetup] | |
public void GlobalSetup() | |
{ | |
Array = new int[Length]; | |
Range = Enumerable.Range(0, Length); | |
Thing = MysteryRange(Length); | |
} | |
static IEnumerable<int> MysteryRange(int count) | |
{ | |
for (int i = 0; i < count; i++) | |
yield return i; | |
} | |
[GlobalCleanup] | |
public void GlobalCleanup() | |
{ | |
// nix | |
} | |
[Benchmark] | |
public void SkipLastNetCoreArrays() { foreach (var a in Array.SkipLast(Count)); } | |
[Benchmark] | |
public void SkipLast1Arrays() { foreach (var a in Array.SkipLast1(Count)); } | |
[Benchmark] | |
public void SkipLast2Arrays() { foreach (var a in Array.SkipLast2(Count)); } | |
[Benchmark] | |
public void SkipLast3Arrays() { foreach (var a in Array.SkipLast3(Count)); } | |
[Benchmark] | |
public void SkipLast4Arrays() { foreach (var a in Array.SkipLast4(Count)); } | |
[Benchmark] | |
public void SkipLast1Ranges() { foreach (var a in Range.SkipLast1(Count)); } | |
[Benchmark] | |
public void SkipLast2Ranges() { foreach (var a in Range.SkipLast2(Count)); } | |
[Benchmark] | |
public void SkipLast3Ranges() { foreach (var a in Range.SkipLast3(Count)); } | |
[Benchmark] | |
public void SkipLast4Ranges() { foreach (var a in Range.SkipLast4(Count)); } | |
[Benchmark] | |
public void SkipLastNetCoreThings() { foreach (var a in Thing.SkipLast(Count)); } | |
[Benchmark] | |
public void SkipLast1Things() { foreach (var a in Thing.SkipLast1(Count)); } | |
[Benchmark] | |
public void SkipLast2Things() { foreach (var a in Thing.SkipLast2(Count)); } | |
[Benchmark] | |
public void SkipLast3Things() { foreach (var a in Thing.SkipLast3(Count)); } | |
[Benchmark] | |
public void SkipLast4Things() { foreach (var a in Thing.SkipLast4(Count)); } | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
SkipLastBenchmark.Bench-20190706-113102
Legends