1
0
mirror of https://github.com/oliverbooth/X10D synced 2024-11-24 00:08:48 +00:00

feat: add IList<T>.Rotate and Span<T>.Rotate

This commit is contained in:
Oliver Booth 2024-11-17 02:24:41 +00:00
parent 51e7d00c48
commit 87090dae98
Signed by: oliverbooth
GPG Key ID: 2A862C3F46178E8E
5 changed files with 149 additions and 0 deletions

View File

@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## 5.0.0 - [Unreleased]
### Added
- X1OD: Added `IList<T>.Rotate(int)`.
- X1OD: Added `Span<T>.Rotate(int)`.
### Changed
- X10D: Removed `IEnumerable<T>.GreatestCommonFactor` for all integer types in favour of generic math.

View File

@ -211,6 +211,46 @@ internal class ListTests
Assert.That(list, Is.EqualTo(new[] { 1, 2, 7, 8, 9, 10 }).AsCollection);
}
[Test]
public void Rotate_ShouldShiftElements_ByNegativeShiftAmount()
{
int[] array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
int[] expected = [5, 6, 7, 8, 9, 10, 1, 2, 3, 4];
array.Rotate(-4);
Assert.That(array, Is.EqualTo(expected).AsCollection);
}
[Test]
public void Rotate_ShouldShiftElements_ByPositiveShiftAmount()
{
int[] array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
int[] expected = [7, 8, 9, 10, 1, 2, 3, 4, 5, 6];
array.Rotate(4);
Assert.That(array, Is.EqualTo(expected).AsCollection);
}
[Test]
public void Rotate_ShouldNotShiftElements_WithShift0()
{
int[] array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
int[] expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
array.Rotate(0);
Assert.That(array, Is.EqualTo(expected).AsCollection);
}
[Test]
public void Rotate_ShouldThrowArgumentNullException_GivenNullSource()
{
int[] array = null!;
Assert.Throws<ArgumentNullException>(() => array.Rotate(0));
}
[Test]
public void Shuffle_ShouldReorder_GivenNotNull()
{

View File

@ -1,4 +1,5 @@
using NUnit.Framework;
using X10D.Collections;
#if !NET9_0_OR_GREATER
using X10D.Collections;
#endif
@ -32,6 +33,39 @@ internal class SpanTest
Assert.That(span.ToArray(), Is.EqualTo(new[] { 1, 2, 3, 2, 5, 2, 7, 2, 9, 2, 11, 2, 13, 2, 15, 2 }));
}
[Test]
public void Rotate_ShouldShiftElements_ByNegativeShiftAmount()
{
Span<int> array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
Span<int> expected = [5, 6, 7, 8, 9, 10, 1, 2, 3, 4];
array.Rotate(-4);
Assert.That(array.ToArray(), Is.EqualTo(expected.ToArray()).AsCollection);
}
[Test]
public void Rotate_ShouldShiftElements_ByPositiveShiftAmount()
{
Span<int> array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
Span<int> expected = [7, 8, 9, 10, 1, 2, 3, 4, 5, 6];
array.Rotate(4);
Assert.That(array.ToArray(), Is.EqualTo(expected.ToArray()).AsCollection);
}
[Test]
public void Rotate_ShouldNotShiftElements_WithShift0()
{
Span<int> array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
Span<int> expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
array.Rotate(0);
Assert.That(array.ToArray(), Is.EqualTo(expected.ToArray()).AsCollection);
}
#if !NET9_0_OR_GREATER
[Test]
public void Split_OnEmptySpan_ShouldYieldNothing_UsingCharDelimiter_GivenReadOnlySpan()

View File

@ -1,5 +1,6 @@
using System.Diagnostics.Contracts;
using X10D.Core;
using X10D.Math;
#pragma warning disable CA5394
@ -249,6 +250,42 @@ public static class ListExtensions
}
}
/// <summary>
/// Shifts the elements of the current list by a specified amount, wrapping them in the process.
/// </summary>
/// <param name="source">The list of elements to shift.</param>
/// <param name="shift">The amount to shift.</param>
/// <typeparam name="T">The type of the elements in <paramref name="source" />.</typeparam>
/// <exception cref="ArgumentNullException"><paramref name="source" /> is <see langword="null" />.</exception>
public static void Rotate<T>(this IList<T> source, int shift)
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
if (shift == 0)
{
return;
}
shift = shift.Mod(source.Count);
Reverse(source, 0, source.Count - 1);
Reverse(source, 0, shift - 1);
Reverse(source, shift, source.Count - 1);
return;
static void Reverse(IList<T> list, int start, int end)
{
while (start < end)
{
(list[start], list[end]) = (list[end], list[start]);
start++;
end--;
}
}
}
/// <summary>
/// Reorganizes the elements in a list by implementing a Fisher-Yates shuffle.
/// </summary>

View File

@ -1,3 +1,5 @@
using X10D.Math;
namespace X10D.Collections;
/// <summary>
@ -16,6 +18,37 @@ public static class SpanExtensions
return source;
}
/// <summary>
/// Shifts the elements of the current span by a specified amount, wrapping them in the process.
/// </summary>
/// <param name="source">The span of elements to shift.</param>
/// <param name="shift">The amount to shift.</param>
/// <typeparam name="T">The type of the elements in <paramref name="source" />.</typeparam>
/// <exception cref="ArgumentNullException"><paramref name="source" /> is <see langword="null" />.</exception>
public static void Rotate<T>(this Span<T> source, int shift)
{
if (shift == 0)
{
return;
}
shift = shift.Mod(source.Length);
Reverse(source, 0, source.Length - 1);
Reverse(source, 0, shift - 1);
Reverse(source, shift, source.Length - 1);
return;
static void Reverse(Span<T> span, int start, int end)
{
while (start < end)
{
(span[start], span[end]) = (span[end], span[start]);
start++;
end--;
}
}
}
#if !NET9_0_OR_GREATER
/// <summary>
/// Splits a span of elements into sub-spans based on a delimiting element.