diff --git a/Containers.Test/ContiguousSetTests.cs b/Containers.Test/ContiguousSetTests.cs index 321ff2f..dd99782 100644 --- a/Containers.Test/ContiguousSetTests.cs +++ b/Containers.Test/ContiguousSetTests.cs @@ -452,4 +452,37 @@ public void WorksWithStrings() Assert.Contains("alpha", set); Assert.Contains("bravo", set); } + + [TestMethod] + public void Remove_WithCustomComparer_RemovesItemEqualOnlyUnderComparer() + { + // Arrange + ContiguousSet set = new(StringComparer.OrdinalIgnoreCase) { "Apple", "Banana" }; + + // Act + bool removed = set.Remove("APPLE"); + + // Assert + Assert.IsTrue(removed); + Assert.HasCount(1, set); + Assert.IsFalse(set.Contains("apple")); + string[] expectedItems = ["Banana"]; + Assert.AreSequenceEqual(expectedItems, set); + } + + [TestMethod] + public void Remove_WithCustomComparer_ThenAdd_KeepsSingleElement() + { + // Arrange + ContiguousSet set = new(StringComparer.OrdinalIgnoreCase) { "Apple" }; + + // Act + set.Remove("APPLE"); + set.Add("apple"); + + // Assert + Assert.HasCount(1, set); + string[] expectedItems = ["apple"]; + Assert.AreSequenceEqual(expectedItems, set); + } } diff --git a/Containers.Test/InsertionOrderSetTests.cs b/Containers.Test/InsertionOrderSetTests.cs index 7e198bc..9eb498c 100644 --- a/Containers.Test/InsertionOrderSetTests.cs +++ b/Containers.Test/InsertionOrderSetTests.cs @@ -322,4 +322,37 @@ public void WorksWithStrings_MaintainsInsertionOrder() Assert.AreEqual("alpha", set.ElementAt(1)); // Second unique Assert.AreEqual("bravo", set.ElementAt(2)); // Third unique } + + [TestMethod] + public void Remove_WithCustomComparer_RemovesItemEqualOnlyUnderComparer() + { + // Arrange + InsertionOrderSet set = new(StringComparer.OrdinalIgnoreCase) { "Apple", "Banana" }; + + // Act + bool removed = set.Remove("APPLE"); + + // Assert + Assert.IsTrue(removed); + Assert.HasCount(1, set); + Assert.IsFalse(set.Contains("apple")); + string[] expectedItems = ["Banana"]; + Assert.AreSequenceEqual(expectedItems, set); + } + + [TestMethod] + public void Remove_WithCustomComparer_ThenAdd_KeepsSingleElement() + { + // Arrange + InsertionOrderSet set = new(StringComparer.OrdinalIgnoreCase) { "Apple" }; + + // Act + set.Remove("APPLE"); + set.Add("apple"); + + // Assert + Assert.HasCount(1, set); + string[] expectedItems = ["apple"]; + Assert.AreSequenceEqual(expectedItems, set); + } } diff --git a/Containers/ContiguousSet.cs b/Containers/ContiguousSet.cs index bc60ff1..37c3f9b 100644 --- a/Containers/ContiguousSet.cs +++ b/Containers/ContiguousSet.cs @@ -281,8 +281,19 @@ public bool Remove(T item) return false; } - // Find and remove from the array - int index = Array.IndexOf(items, item, 0, Count); + // Find and remove from the array, matching with the set's comparer so an item that is + // equal only under a custom comparer is removed from storage as well as the hash set + IEqualityComparer comparer = uniquenessSet.Comparer; + int index = -1; + for (int i = 0; i < Count; i++) + { + if (comparer.Equals(items[i], item)) + { + index = i; + break; + } + } + if (index >= 0) { Count--; diff --git a/Containers/InsertionOrderSet.cs b/Containers/InsertionOrderSet.cs index 9b92842..cf6105e 100644 --- a/Containers/InsertionOrderSet.cs +++ b/Containers/InsertionOrderSet.cs @@ -237,7 +237,15 @@ public bool Remove(T item) return false; } - items.Remove(item); + // Match with the set's comparer so an item that is equal only under a custom comparer + // is removed from the list as well as the hash set + IEqualityComparer comparer = uniquenessSet.Comparer; + int index = items.FindIndex(x => comparer.Equals(x, item)); + if (index >= 0) + { + items.RemoveAt(index); + } + return true; }