diff --git a/Recyclable.Collections/Recyclable.Collections.csproj b/Recyclable.Collections/Recyclable.Collections.csproj
index b29d18c..1be10da 100644
--- a/Recyclable.Collections/Recyclable.Collections.csproj
+++ b/Recyclable.Collections/Recyclable.Collections.csproj
@@ -15,10 +15,17 @@
Recyclable.Collections project is an open source framework for operating dynamic lists at performance close to raw arrays. It aims at providing high performance with minimal memory footprint. It implements IList<T>'s interface and is targeted as direct replacements of List<T>, SortableList<T>, PriorityQueue<T> and similar.
The project & source code is free for educational, open-source & personal use.
+ https://github.com/mlemanczyk/Recyclable.Collections
+ https://github.com/mlemanczyk/Recyclable.Collections
+ Marek Lemańczyk 2023
+ https://github.com/mlemanczyk/Recyclable.Collections
+ /README.md
-
+
+ PreserveNewest
+
diff --git a/Recyclable.Collections/RecyclableSortedList.cs b/Recyclable.Collections/RecyclableSortedList.cs
new file mode 100644
index 0000000..78f3382
--- /dev/null
+++ b/Recyclable.Collections/RecyclableSortedList.cs
@@ -0,0 +1,43 @@
+namespace Recyclable.Collections
+{
+ public class RecyclableSortedList : RecyclableList<(TKey Key, TValue Value)>
+ where TKey : notnull
+ {
+ private static readonly IComparer<(TKey, TValue)> _comparer = new FrequencyTupleComparer();
+ private readonly SystemRandomNumberGenerator _randomNumberGenerator = new SystemRandomNumberGenerator();
+
+ protected override void ListUpdated()
+ {
+ base.ListUpdated();
+ QuickSort();
+ }
+
+ public RecyclableSortedList() : base()
+ {
+ }
+
+ public RecyclableSortedList(Dictionary source, int blockSize = RecyclableDefaults.BlockSize)
+ : this(source.Select(x => (x.Key, x.Value)), blockSize)
+ {
+ }
+
+ public RecyclableSortedList(IEnumerable<(TKey Key, TValue Value)> source, int blockSize = RecyclableDefaults.BlockSize)
+ : base(source, blockSize)
+ {
+ QuickSort();
+ }
+
+ public void QuickSort()
+ {
+ _isUpdating++;
+ try
+ {
+ this.QuickSort(_comparer, _randomNumberGenerator);
+ }
+ finally
+ {
+ _isUpdating--;
+ }
+ }
+ }
+}
diff --git a/Recyclable.CollectionsTests/Recyclable.CollectionsTests.csproj b/Recyclable.CollectionsTests/Recyclable.CollectionsTests.csproj
index df55634..12982dd 100644
--- a/Recyclable.CollectionsTests/Recyclable.CollectionsTests.csproj
+++ b/Recyclable.CollectionsTests/Recyclable.CollectionsTests.csproj
@@ -1,4 +1,4 @@
-
+
net6.0
@@ -8,10 +8,6 @@
false
-
-
-
-
diff --git a/Recyclable.CollectionsTests/RecyclableSortedListTests.cs b/Recyclable.CollectionsTests/RecyclableSortedListTests.cs
new file mode 100644
index 0000000..0096f7f
--- /dev/null
+++ b/Recyclable.CollectionsTests/RecyclableSortedListTests.cs
@@ -0,0 +1,88 @@
+using FluentAssertions;
+using Recyclable.Collections;
+
+namespace Recyclable.CollectionsTests
+{
+ [TestClass()]
+ public class RecyclableSortedListTests
+ {
+ private static readonly (int, string)[] _testData = new[] { (5, "a"), (4, "d"), (3, "c"), (2, "b"), (1, "a") };
+
+ [TestMethod]
+ public void ShouldBeSortedWhenCreated()
+ {
+ // Act
+ using var sortedList = new RecyclableSortedList(_testData);
+
+ // Validate
+ _ = sortedList.Should().HaveCount(_testData.Length)
+ .And.BeEquivalentTo(_testData)
+ .And.BeInAscendingOrder((item) => item.Key);
+ }
+
+ [TestMethod]
+ public void ShouldBeEmptyWhenNotInitialized()
+ {
+ // Act
+ using var sortedList = new RecyclableSortedList();
+
+ // Validate
+ _ = sortedList.Should().BeEmpty();
+ }
+
+ [TestMethod]
+ public void ShouldBeSortedWhenInitialized()
+ {
+ // Act
+ using var sortedList = new RecyclableSortedList()
+ {
+ _testData[0],
+ _testData[1],
+ _testData[2],
+ _testData[3],
+ _testData[4]
+ };
+
+ // Validate
+ _ = sortedList.Should().NotBeEmpty()
+ .And.BeInAscendingOrder(x => x.Key)
+ .And.BeEquivalentTo(_testData);
+ }
+
+ [TestMethod]
+ public void ShouldBeSortedWhenUpdateEnds()
+ {
+ // Prepare
+ using var sortedList = new RecyclableSortedList();
+
+ // Act
+ sortedList.BeginUpdate();
+ foreach (var testItem in _testData)
+ {
+ sortedList.Add(testItem);
+ }
+
+ // Validate
+ _ = sortedList.Should().BeInDescendingOrder(x => x.Key);
+
+ // Act
+ sortedList.EndUpdate();
+
+ // Validate
+ _ = sortedList.Should().BeInAscendingOrder(x => x.Key);
+ }
+
+ [TestMethod]
+ public void ShouldBeEmptyAfterClear()
+ {
+ // Prepare
+ using var sortedList = new RecyclableSortedList(_testData);
+
+ // Act
+ sortedList.Clear();
+
+ // Validate
+ _ = sortedList.Should().BeEmpty();
+ }
+ }
+}
\ No newline at end of file