diff --git a/collections-arrays/SliceArrays/SliceArrayTests/SliceArrayTests.cs b/collections-arrays/SliceArrays/SliceArrayTests/SliceArrayTests.cs index 5457caf67f..e9d7e29baf 100644 --- a/collections-arrays/SliceArrays/SliceArrayTests/SliceArrayTests.cs +++ b/collections-arrays/SliceArrays/SliceArrayTests/SliceArrayTests.cs @@ -1,84 +1,188 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System; +using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; -namespace SliceArrayTests +namespace SliceArrayTests; + +[TestClass] +public class SliceArrayTests { - [TestClass] - public class SliceArrayTests + [TestMethod] + public void WhenUsingLINQ_ThenArrayIsSliced() + { + var posts = new string[] { "post1", "post2", "post3", "post4", "post5", "post6", "post7", "post8", "post9", "post10" }; + + var slicedPosts = posts.Skip(0).Take(5); + + Assert.AreEqual(5, slicedPosts.Count()); + } + + [TestMethod] + public void WhenUsingCopy_ThenArrayIsSliced() + { + var posts = new string[] { "post1", "post2", "post3", "post4", "post5", "post6", "post7", "post8", "post9", "post10" }; + + var slicedPosts = new string[5]; + Array.Copy(posts, 0, slicedPosts, 0, 5); + + Assert.AreEqual(5, slicedPosts.Count()); + } + + [TestMethod] + public void WhenUsingArraySegment_ThenArrayIsSliced() + { + var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; + + var trainingData = new ArraySegment>(data, 0, 3); + var testingData = new ArraySegment>(data, 3, 2); + + Assert.AreEqual(3, trainingData.Count()); + Assert.AreEqual(2, testingData.Count()); + } + + [TestMethod] + public void WhenUsingArraySegmentSlice_ThenArrayIsSliced() + { + var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; + + var arraySegment = new ArraySegment>(data); + var trainingData = arraySegment.Slice(0, 3); + var testingData = arraySegment.Slice(3, 2); + + Assert.AreEqual(3, trainingData.Count()); + Assert.AreEqual(2, testingData.Count()); + } + + [TestMethod] + public void WhenUsingReadOnlySpan_ThenArrayIsSliced() + { + var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; + + var trainingData = new ReadOnlySpan>(data, 0, 3); + var testingData = new ReadOnlySpan>(data, 3, 2); + + Assert.AreEqual(3, trainingData.Length); + Assert.AreEqual(2, testingData.Length); + } + + [TestMethod] + public void WhenUsingAsSpan_ThenArrayIsSlicedWithoutCopying() + { + var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; + + var trainingData = data.AsSpan(0, 3); + var testingData = data.AsSpan(3); + trainingData[0] = new(40, false); + + Assert.AreEqual(3, trainingData.Length); + Assert.AreEqual(2, testingData.Length); + Assert.AreEqual(new Tuple(40, false), data[0]); + } + + [TestMethod] + public void WhenUsingSpanSlice_ThenSpanIsSliced() + { + var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; + + var trainingData = data.AsSpan(0, 3); + var firstTwo = trainingData.Slice(0, 2); + + Assert.AreEqual(2, firstTwo.Length); + Assert.AreEqual(data[1], firstTwo[1]); + } + + [TestMethod] + public void WhenUsingIndexFromEnd_ThenLastElementsAreSliced() { - [TestMethod] - public void WhenUsingLINQ_ThenArrayIsSliced() - { - var posts = new string[] { "post1", "post2", "post3", "post4", "post5", "post6", "post7", "post8", "post9", "post10" }; - - var slicedPosts = posts.Skip(0).Take(5); - - Assert.AreEqual(5, slicedPosts.Count()); - } - - [TestMethod] - public void WhenUsingCopy_ThenArrayIsSliced() - { - var posts = new string[] { "post1", "post2", "post3", "post4", "post5", "post6", "post7", "post8", "post9", "post10" }; - - var slicedPosts = new string[5]; - Array.Copy(posts, 0, slicedPosts, 0, 5); - - Assert.AreEqual(5, slicedPosts.Count()); - } - - [TestMethod] - public void WhenUsingArraySegment_ThenArrayIsSliced() - { - var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; - - var trainingData = new ArraySegment>(data, 0, 3); - var testingData = new ArraySegment>(data, 3, 2); - - Assert.AreEqual(3, trainingData.Count()); - Assert.AreEqual(2, testingData.Count()); - } - - [TestMethod] - public void WhenUsingArraySegmentSlice_ThenArrayIsSliced() - { - var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; - - var arraySegment = new ArraySegment>(data); - var trainingData = arraySegment.Slice(0, 3); - var testingData = arraySegment.Slice(3, 2); - - Assert.AreEqual(3, trainingData.Count()); - Assert.AreEqual(2, testingData.Count()); - } - - [TestMethod] - public void WhenUsingReadOnlySpan_ThenArrayIsSliced() - { - var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; - - var trainingData = new ReadOnlySpan>(data, 0, 3); - var testingData = new ReadOnlySpan>(data, 3, 2); - - Assert.AreEqual(3, trainingData.Length); - Assert.AreEqual(2, testingData.Length); - } - - [TestMethod] - public void WhenUsingRangeOperator_ThenArrayIsSliced() - { - var array = new int[] { 1, 2, 3, 4, 5 }; - - var slice1 = array[2..]; - var slice2 = array[..3]; - var slice3 = array[1..3]; - var slice4 = array[..]; - - Assert.AreEqual(3, slice1.Length); - Assert.AreEqual(3, slice2.Length); - Assert.AreEqual(2, slice3.Length); - Assert.AreEqual(5, slice4.Length); - } + var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; + + var lastTwo = data.AsSpan()[^2..]; + + Assert.AreEqual(2, lastTwo.Length); + Assert.AreEqual(data[3], lastTwo[0]); + Assert.AreEqual(data[4], lastTwo[1]); + } + + [TestMethod] + public void WhenUsingRangeOperator_ThenArrayIsSliced() + { + var array = new int[] { 1, 2, 3, 4, 5 }; + + var slice1 = array[2..]; + var slice2 = array[..2]; + var slice3 = array[1..3]; + var slice4 = array[..]; + + Assert.AreEqual(3, slice1.Length); + Assert.AreEqual(2, slice2.Length); + Assert.AreEqual(2, slice3.Length); + Assert.AreEqual(5, slice4.Length); + } + + [TestMethod] + public void WhenUsingReversedRange_ThenArgumentOutOfRangeExceptionIsThrown() + { + var array = new int[] { 1, 2, 3, 4, 5 }; + + Assert.ThrowsExactly(() => array[3..1]); + } + + [TestMethod] + public void WhenUsingRangeOperatorOnList_ThenListIsCopied() + { + var list = new List { 10, 20, 30, 40, 50 }; + + var slice = list[1..3]; + slice[0] = 777; + + CollectionAssert.AreEqual(new List { 777, 30 }, slice); + Assert.AreEqual(20, list[1]); + } + + [TestMethod] + public void WhenUsingGetRange_ThenListIsCopied() + { + var list = new List { 10, 20, 30, 40, 50 }; + + var slice = list.GetRange(1, 2); + slice[0] = 777; + + Assert.AreEqual(2, slice.Count); + Assert.AreEqual(20, list[1]); + } + + [TestMethod] + public void WhenUsingCollectionsMarshalAsSpan_ThenWritesReachTheList() + { + var list = new List { 10, 20, 30, 40, 50 }; + + var view = CollectionsMarshal.AsSpan(list); + view[1] = 777; + + Assert.AreEqual(5, view.Length); + Assert.AreEqual(777, list[1]); + } + + [TestMethod] + public void WhenUsingRangeOperatorOnString_ThenSubstringIsReturned() + { + var text = "code-maze"; + + var slice = text[5..]; + + Assert.AreEqual("maze", slice); + Assert.AreEqual(text.Substring(5), slice); + } + + [TestMethod] + public void WhenUsingAsSpanOnString_ThenCharactersAreSlicedWithoutCopying() + { + var text = "code-maze"; + + var slice = text.AsSpan(5); + + Assert.AreEqual("maze", slice.ToString()); } } diff --git a/collections-arrays/SliceArrays/SliceArrayTests/SliceArrayTests.csproj b/collections-arrays/SliceArrays/SliceArrayTests/SliceArrayTests.csproj index 0ef0e0cb63..2b290de609 100644 --- a/collections-arrays/SliceArrays/SliceArrayTests/SliceArrayTests.csproj +++ b/collections-arrays/SliceArrays/SliceArrayTests/SliceArrayTests.csproj @@ -1,16 +1,16 @@ - net6.0 + net10.0 false - - - - + + + + diff --git a/collections-arrays/SliceArrays/SliceArrays/Program.cs b/collections-arrays/SliceArrays/SliceArrays/Program.cs index 97969b1dce..059ca7299e 100644 --- a/collections-arrays/SliceArrays/SliceArrays/Program.cs +++ b/collections-arrays/SliceArrays/SliceArrays/Program.cs @@ -1,105 +1,158 @@ -using System; -using System.Linq; +using System.Runtime.InteropServices; -namespace SliceArrays +SliceArrayUsingLINQ(); +SliceArrayUsingCopy(); +SliceArrayUsingArraySegment(); +SliceArrayUsingArraySegmentSlice(); +SliceArrayUsingArraySegmentWithChanging(); +SliceArrayUsingReadOnlySpan(); +SliceArrayUsingSpan(); +SliceArrayUsingRangeOperator(); +SliceArrayUsingReversedRange(); +SliceList(); +SliceString(); + +static void SliceArrayUsingLINQ() +{ + var posts = new string[] { "post1", "post2", "post3", "post4", "post5", "post6", "post7", "post8", "post9", "post10" }; + var slicedPosts = posts.Skip(0).Take(5); + foreach (var post in slicedPosts) + Console.WriteLine(post); // Outputs the first 5 posts +} + +static void SliceArrayUsingCopy() +{ + var posts = new string[] { "post1", "post2", "post3", "post4", "post5", "post6", "post7", "post8", "post9", "post10" }; + var slicedPosts = new string[5]; + Array.Copy(posts, 0, slicedPosts, 0, 5); + foreach (var post in slicedPosts) + Console.WriteLine(post); // Outputs the first 5 posts +} + +static void SliceArrayUsingArraySegment() +{ + var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; + var trainingData = new ArraySegment>(data, 0, 3); + var testingData = new ArraySegment>(data, 3, 2); + + Console.WriteLine("Training Data:"); + foreach (var record in trainingData) + Console.WriteLine(record); + + Console.WriteLine(); + Console.WriteLine("Testing Data:"); + foreach (var record in testingData) + Console.WriteLine(record); +} + +static void SliceArrayUsingArraySegmentSlice() +{ + var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; + var arraySegment = new ArraySegment>(data); + var trainingData = arraySegment.Slice(0, 3); + var testingData = arraySegment.Slice(3, 2); + + Console.WriteLine("Training Data:"); + foreach (var record in trainingData) + Console.WriteLine(record); + + Console.WriteLine(); + Console.WriteLine("Testing Data:"); + foreach (var record in testingData) + Console.WriteLine(record); +} + +static void SliceArrayUsingArraySegmentWithChanging() +{ + var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; + var trainingData = new ArraySegment>(data, 0, 3); + Console.WriteLine("Training Data:"); + for (int i = 0; i < trainingData.Count; i++) + { + trainingData[i] = new(40, false); + Console.WriteLine(trainingData[i]); + } + + Console.WriteLine(); + Console.WriteLine("Original Data:"); + foreach (var record in data) + Console.WriteLine(record); +} + +static void SliceArrayUsingReadOnlySpan() { - class Program + var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; + var trainingData = new ReadOnlySpan>(data, 0, 3); + var testingData = new ReadOnlySpan>(data, 3, 2); + Console.WriteLine("Training Data:"); + foreach (var record in trainingData) + Console.WriteLine(record); + + Console.WriteLine(); + Console.WriteLine("Testing Data:"); + foreach (var record in testingData) + Console.WriteLine(record); +} + +static void SliceArrayUsingSpan() +{ + var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; + var trainingData = data.AsSpan(0, 3); + var testingData = data.AsSpan(3); + + var firstTwo = trainingData.Slice(0, 2); + var lastTwo = data.AsSpan()[^2..]; + + Console.WriteLine($"Training: {trainingData.Length}, testing: {testingData.Length}"); + Console.WriteLine($"First two: {firstTwo[0]}, {firstTwo[1]}"); + Console.WriteLine($"Last two: {lastTwo[0]}, {lastTwo[1]}"); +} + +static void SliceArrayUsingRangeOperator() +{ + var array = new int[] { 1, 2, 3, 4, 5 }; + var slice1 = array[2..]; // From index 2 to the end + var slice2 = array[..2]; // From the start to index 1 + var slice3 = array[1..3]; // From the index 1 to index 2 + var slice4 = array[..]; // The whole array + + Console.WriteLine(string.Join(", ", slice1)); + Console.WriteLine(string.Join(", ", slice2)); + Console.WriteLine(string.Join(", ", slice3)); + Console.WriteLine(string.Join(", ", slice4)); +} + +static void SliceArrayUsingReversedRange() +{ + var array = new int[] { 1, 2, 3, 4, 5 }; + try + { + var slice5 = array[3..1]; // Throws ArgumentOutOfRangeException + } + catch (ArgumentOutOfRangeException ex) { - static void Main(string[] args) - { - SliceArrayUsingRangeOperator(); - } - - static void SliceArrayUsingLINQ() - { - var posts = new string[] { "post1", "post2", "post3", "post4", "post5", "post6", "post7", "post8", "post9", "post10" }; - var slicedPosts = posts.Skip(0).Take(5); - foreach (var post in slicedPosts) - Console.WriteLine(post); // Outputs the first 5 posts - } - - static void SliceArrayUsingCopy() - { - var posts = new string[] { "post1", "post2", "post3", "post4", "post5", "post6", "post7", "post8", "post9", "post10" }; - var slicedPosts = new string[5]; - Array.Copy(posts, 0, slicedPosts, 0, 5); - foreach (var post in slicedPosts) - Console.WriteLine(post); // Outputs the first 5 posts - } - - static void SliceArrayUsingArraySegment() - { - var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; - var trainingData = new ArraySegment>(data, 0, 3); - var testingData = new ArraySegment>(data, 3, 2); - - Console.WriteLine("Training Data:"); - foreach (var record in trainingData) - Console.WriteLine(record); - - Console.WriteLine(); - Console.WriteLine("Testing Data:"); - foreach (var record in testingData) - Console.WriteLine(record); - } - - static void SliceArrayUsingArraySegmentSlice() - { - var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; - var arraySegment = new ArraySegment>(data); - var trainingData = arraySegment.Slice(0, 3); - var testingData = arraySegment.Slice(3, 2); - - Console.WriteLine("Training Data:"); - foreach (var record in trainingData) - Console.WriteLine(record); - - Console.WriteLine(); - Console.WriteLine("Testing Data:"); - foreach (var record in testingData) - Console.WriteLine(record); - } - - static void SliceArrayUsingArraySegmentWithChanging() - { - var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; - var trainingData = new ArraySegment>(data, 0, 3); - Console.WriteLine("Training Data:"); - for (int i = 0; i < trainingData.Count; i++) - { - trainingData[i] = new(40, false); - Console.WriteLine(trainingData[i]); - } - - Console.WriteLine(); - Console.WriteLine("Original Data:"); - foreach (var record in data) - Console.WriteLine(record); - } - - static void SliceArrayUsingReadOnlySpan() - { - var data = new Tuple[] { new(20, true), new(50, true), new(35, false), new(55, true), new(16, false) }; - var trainingData = new ReadOnlySpan>(data, 0, 3); - var testingData = new ReadOnlySpan>(data, 3, 2); - Console.WriteLine("Training Data:"); - foreach (var record in trainingData) - Console.WriteLine(record); - - Console.WriteLine(); - Console.WriteLine("Testing Data:"); - foreach (var record in testingData) - Console.WriteLine(record); - } - - static void SliceArrayUsingRangeOperator() - { - var array = new int[] { 1, 2, 3, 4, 5 }; - var slice1 = array[2..]; // From index 2 to the end - var slice2 = array[..3]; // From the start to index 2 - var slice3 = array[1..3]; // From the index 1 to index 2 - var slice4 = array[..]; // The whole array - var slice5 = array[3..1]; // Throws ArgumentOutOfRangeException - } + Console.WriteLine($"array[3..1] throws {ex.GetType().Name}"); } } + +static void SliceList() +{ + var list = new List { 10, 20, 30, 40, 50 }; + var rangeCopy = list[1..3]; // .NET 8 and later + var getRangeCopy = list.GetRange(1, 2); // Every version + var view = CollectionsMarshal.AsSpan(list); + + Console.WriteLine(string.Join(", ", rangeCopy)); + Console.WriteLine(string.Join(", ", getRangeCopy)); + Console.WriteLine($"View length: {view.Length}"); +} + +static void SliceString() +{ + var text = "code-maze"; + var copy = text[5..]; + var view = text.AsSpan(5); + + Console.WriteLine(copy); + Console.WriteLine(view.ToString()); +} diff --git a/collections-arrays/SliceArrays/SliceArrays/SliceArrays.csproj b/collections-arrays/SliceArrays/SliceArrays/SliceArrays.csproj index 41f1d5ad4b..dfb40caafc 100644 --- a/collections-arrays/SliceArrays/SliceArrays/SliceArrays.csproj +++ b/collections-arrays/SliceArrays/SliceArrays/SliceArrays.csproj @@ -2,7 +2,9 @@ Exe - net6.0 + net10.0 + enable + enable