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:
parent
51e7d00c48
commit
87090dae98
@ -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.
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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()
|
||||
|
@ -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>
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user