diff --git a/Containers.Test/OrderedSetTests.cs b/Containers.Test/OrderedSetTests.cs
index dad6539..0610cec 100644
--- a/Containers.Test/OrderedSetTests.cs
+++ b/Containers.Test/OrderedSetTests.cs
@@ -624,6 +624,86 @@ public void LargeDataSet_MaintainsPerformanceAndOrder()
Assert.HasCount(result.Length, result.Distinct(), "All elements should be unique");
}
+ ///
+ /// Builds a set whose notion of equality is case-insensitive, so that the set's own comparer
+ /// and disagree about which strings are the same.
+ ///
+ private static OrderedSet CaseInsensitiveSet(params string[] items) =>
+ new(items, StringComparer.OrdinalIgnoreCase);
+
+ [TestMethod]
+ public void IntersectWith_CustomComparer_KeepsElementsThatMatchUnderThatComparer()
+ {
+ OrderedSet set = CaseInsensitiveSet("Hello", "World");
+
+ set.IntersectWith(["HELLO"]);
+
+ Assert.HasCount(1, set, "Only the element matching under the set's comparer should remain");
+ Assert.IsTrue(set.Contains("Hello"), "\"Hello\" matches \"HELLO\" under the set's comparer and must survive");
+ }
+
+ [TestMethod]
+ public void IsSubsetOf_CustomComparer_MatchesUnderThatComparer()
+ {
+ OrderedSet set = CaseInsensitiveSet("Hello");
+
+ Assert.IsTrue(set.IsSubsetOf(["HELLO", "World"]), "\"Hello\" is contained in the collection under the set's comparer");
+ }
+
+ [TestMethod]
+ public void IsProperSubsetOf_CustomComparer_MatchesUnderThatComparer()
+ {
+ OrderedSet set = CaseInsensitiveSet("Hello");
+
+ Assert.IsTrue(set.IsProperSubsetOf(["HELLO", "World"]), "The set is a strictly smaller subset under its own comparer");
+ }
+
+ [TestMethod]
+ public void IsProperSubsetOf_CustomComparer_CountsDistinctElementsUnderThatComparer()
+ {
+ OrderedSet set = CaseInsensitiveSet("Hello");
+
+ Assert.IsFalse(
+ set.IsProperSubsetOf(["HELLO", "hello"]),
+ "The collection holds one distinct element under the set's comparer, so the set is not strictly smaller"
+ );
+ }
+
+ [TestMethod]
+ public void IsProperSupersetOf_CustomComparer_CountsDistinctElementsUnderThatComparer()
+ {
+ OrderedSet set = CaseInsensitiveSet("Hello", "World");
+
+ Assert.IsTrue(
+ set.IsProperSupersetOf(["HELLO", "hello"]),
+ "The collection holds one distinct element under the set's comparer, so the set is strictly larger"
+ );
+ }
+
+ [TestMethod]
+ public void SetEquals_CustomComparer_CountsDistinctElementsUnderThatComparer()
+ {
+ OrderedSet set = CaseInsensitiveSet("Hello", "World");
+
+ Assert.IsTrue(
+ set.SetEquals(["HELLO", "hello", "WORLD"]),
+ "The collection holds the same two distinct elements under the set's comparer"
+ );
+ }
+
+ [TestMethod]
+ public void SymmetricExceptWith_CustomComparer_TreatsMatchesUnderThatComparerAsCommon()
+ {
+ OrderedSet set = CaseInsensitiveSet("Hello", "World");
+
+ set.SymmetricExceptWith(["HELLO", "Foo"]);
+
+ Assert.HasCount(2, set, "The common element should be dropped and the unmatched one added");
+ Assert.IsFalse(set.Contains("Hello"), "\"Hello\" is common to both under the set's comparer and must be dropped");
+ Assert.IsTrue(set.Contains("World"), "\"World\" is only in the set and must remain");
+ Assert.IsTrue(set.Contains("Foo"), "\"Foo\" is only in the other collection and must be added");
+ }
+
[TestMethod]
public void StressTest_MultipleOperations()
{
diff --git a/Containers/OrderedSet.cs b/Containers/OrderedSet.cs
index b02cd67..dd584c9 100644
--- a/Containers/OrderedSet.cs
+++ b/Containers/OrderedSet.cs
@@ -311,6 +311,19 @@ public int BinarySearch(T item)
return ~left; // Return bitwise complement of insertion point
}
+ ///
+ /// Materializes into a set that uses this set's comparer.
+ ///
+ /// The collection to materialize.
+ /// A set containing the distinct elements of , as this set defines distinctness.
+ ///
+ /// The set operations need both membership tests and a cardinality for .
+ /// Building a here would answer both with ,
+ /// which disagrees with whenever a custom comparer was supplied, so the
+ /// temporary set is built with instead.
+ ///
+ private OrderedSet ToComparerSet(IEnumerable other) => new(other, Comparer);
+
///
/// Returns an enumerator that iterates through the set in sorted order.
///
@@ -348,7 +361,7 @@ public void IntersectWith(IEnumerable other)
{
Ensure.NotNull(other);
- HashSet otherSet = [.. other];
+ OrderedSet otherSet = ToComparerSet(other);
for (int i = items.Count - 1; i >= 0; i--)
{
@@ -383,7 +396,7 @@ public void SymmetricExceptWith(IEnumerable other)
{
Ensure.NotNull(other);
- HashSet otherSet = [.. other];
+ OrderedSet otherSet = ToComparerSet(other);
// Create a list of items to remove from otherSet as we find them
List toRemoveFromOther = [];
@@ -421,7 +434,7 @@ public bool IsSubsetOf(IEnumerable other)
{
Ensure.NotNull(other);
- HashSet otherSet = [.. other];
+ OrderedSet otherSet = ToComparerSet(other);
return items.All(otherSet.Contains);
}
@@ -448,8 +461,8 @@ public bool IsProperSubsetOf(IEnumerable other)
{
Ensure.NotNull(other);
- HashSet otherSet = [.. other];
- return Count < otherSet.Count && IsSubsetOf(otherSet);
+ OrderedSet otherSet = ToComparerSet(other);
+ return Count < otherSet.Count && items.All(otherSet.Contains);
}
///
@@ -462,7 +475,7 @@ public bool IsProperSupersetOf(IEnumerable other)
{
Ensure.NotNull(other);
- HashSet otherSet = [.. other];
+ OrderedSet otherSet = ToComparerSet(other);
return Count > otherSet.Count && IsSupersetOf(otherSet);
}
@@ -489,8 +502,8 @@ public bool SetEquals(IEnumerable other)
{
Ensure.NotNull(other);
- HashSet otherSet = [.. other];
- return Count == otherSet.Count && IsSubsetOf(otherSet);
+ OrderedSet otherSet = ToComparerSet(other);
+ return Count == otherSet.Count && items.All(otherSet.Contains);
}
///