/// <summary> /// Computes the difference of this bag with another bag. The difference of these two bags /// is all items that appear in this bag, but not in <paramref name="otherBag"/>. If an item appears X times in this bag, /// and Y times in the other bag, the difference contains the item X - Y times (zero times if Y >= X). This bag receives /// the difference of the two bags; the other bag is unchanged. /// </summary> /// <remarks> /// <para>The difference of two bags is computed in time O(M), where M is the size of the /// other bag.</para> /// </remarks> /// <param name="otherBag">Bag to difference with.</param> /// <exception cref="InvalidOperationException">This bag and <paramref name="otherBag"/> don't use the same method for comparing items.</exception> public void DifferenceWith(Bag <T> otherBag) { CheckConsistentComparison(otherBag); if (this == otherBag) { Clear(); return; } // Enumerate each of the items in the other bag. Remove items that need to be // removed from this bag. foreach (T item in otherBag.DistinctItems()) { var copiesInThis = NumberOfCopies(item); var copiesInOther = otherBag.NumberOfCopies(item); var copies = copiesInThis - copiesInOther; if (copies < 0) { copies = 0; } ChangeNumberOfCopies(item, copies); } }
/// <summary> /// Determines if this bag is a superset of another bag. Neither bag is modified. /// This bag is a superset of <paramref name="otherBag"/> if every element in /// <paramref name="otherBag"/> is also in this bag, at least the same number of /// times. /// </summary> /// <remarks>IsSupersetOf is computed in time O(M), where M is the number of unique items in /// <paramref name="otherBag"/>.</remarks> /// <param name="otherBag">Bag to compare to.</param> /// <returns>True if this is a superset of <paramref name="otherBag"/>.</returns> /// <exception cref="InvalidOperationException">This bag and <paramref name="otherBag"/> don't use the same method for comparing items.</exception> public bool IsSupersetOf(Bag <T> otherBag) { CheckConsistentComparison(otherBag); if (otherBag.Count > Count) { return(false); // Can't be a superset of a bigger set } // Check each item in the other set to make sure it is in this set. return(otherBag.DistinctItems().All(item => NumberOfCopies(item) >= otherBag.NumberOfCopies(item))); }
/// <summary> /// Determines if this bag is equal to another bag. This bag is equal to /// <paramref name="otherBag"/> if they contain the same number of /// of copies of equal elements. /// </summary> /// <remarks>IsSupersetOf is computed in time O(N), where N is the number of unique items in /// this bag.</remarks> /// <param name="otherBag">Bag to compare to</param> /// <returns>True if this bag is equal to <paramref name="otherBag"/>, false otherwise.</returns> /// <exception cref="InvalidOperationException">This bag and <paramref name="otherBag"/> don't use the same method for comparing items.</exception> public bool IsEqualTo(Bag <T> otherBag) { CheckConsistentComparison(otherBag); // Must be the same size. if (otherBag.Count != Count) { return(false); } // Check each item to make sure it is in this set the same number of times. return(otherBag.DistinctItems().All(item => NumberOfCopies(item) == otherBag.NumberOfCopies(item))); }
public void CloneContents() { var bag1 = new Bag <MyInt>(); MyInt mi = new MyInt(9); bag1.Add(new MyInt(14)); bag1.Add(new MyInt(143)); bag1.Add(new MyInt(2)); bag1.Add(mi); bag1.Add(null); bag1.Add(new MyInt(14)); bag1.Add(new MyInt(111)); bag1.Add(mi); Bag <MyInt> bag2 = bag1.CloneContents(); CompareClones(bag1, bag2); var bag3 = new Bag <int>(new int[] { 144, 1, 5, 23, 1, 8 }); var bag4 = bag3.CloneContents(); CompareClones(bag3, bag4); var bag5 = new Bag <UtilFixture.CloneableStruct> { new UtilFixture.CloneableStruct(143), new UtilFixture.CloneableStruct(1), new UtilFixture.CloneableStruct(23), new UtilFixture.CloneableStruct(1), new UtilFixture.CloneableStruct(8) }; var bag6 = bag5.CloneContents(); Assert.AreEqual(bag5.Count, bag6.Count); // Check that the bags are equal, but not identical (e.g., have been cloned via ICloneable). foreach (var item in bag5) { var found = 0; foreach (var other in bag6) { if (Equals(item, other)) { found += 1; // Assert.IsFalse(item.Identical(other)); } } Assert.AreEqual(bag5.NumberOfCopies(item), found); } }
public void RandomAddDelete() { const int SIZE = 5000; var count = new int[SIZE]; var rand = new Random(3); var bag1 = new Bag <int>(); bool b; // Add and delete values at random. for (int i = 0; i < SIZE * 100; ++i) { int v = rand.Next(SIZE); Assert.AreEqual(count[v], bag1.NumberOfCopies(v)); if (count[v] > 0) { Assert.IsTrue(bag1.Contains(v)); } if (count[v] == 0 || rand.Next(2) == 1) { // Add to the bag. bag1.Add(v); count[v] += 1; } else { // Remove from the bag. b = bag1.Remove(v); Assert.IsTrue(b); count[v] -= 1; } } // Make sure the bag has all the correct values, not necessarily in order. int c = count.Sum(); Assert.AreEqual(c, bag1.Count); foreach (var v in bag1) { --count[v]; } foreach (var x in count) { Assert.AreEqual(0, x); } }
private void CompareClones <T>(Bag <T> s1, Bag <T> s2) { Assert.AreEqual(s1.Count, s2.Count); // Check that the sets are equal, but not reference equals (e.g., have been cloned). foreach (T item in s1) { var found = 0; foreach (T other in s2) { if (Equals(item, other)) { found += 1; //if(item != null) // Assert.IsFalse(ReferenceEquals(item, other)); } } Assert.AreEqual(s1.NumberOfCopies(item), found); } }
/// <summary> /// Computes the sum of this bag with another bag. The sum of two bags /// is all items from both of the bags. If an item appears X times in one bag, /// and Y times in the other bag, the sum contains the item (X+Y) times. This bag receives /// the sum of the two bags, the other bag is unchanged. /// </summary> /// <remarks> /// <para>The sum of two bags is computed in time O(M), where M is the size of the /// other bag..</para> /// </remarks> /// <param name="otherBag">Bag to sum with.</param> /// <exception cref="InvalidOperationException">This bag and <paramref name="otherBag"/> don't use the same method for comparing items.</exception> public void SumWith(Bag <T> otherBag) { CheckConsistentComparison(otherBag); if (this == otherBag) { // Not very efficient, but an uncommon case. AddMany(otherBag); return; } // Enumerate each of the items in the other bag. Add items that need to be // added to this bag. foreach (var item in otherBag.DistinctItems()) { var copiesInThis = NumberOfCopies(item); var copiesInOther = otherBag.NumberOfCopies(item); ChangeNumberOfCopies(item, copiesInThis + copiesInOther); } }
/// <summary> /// Computes the union of this bag with another bag. The union of two bags /// is all items from both of the bags. If an item appears X times in one bag, /// and Y times in the other bag, the union contains the item Maximum(X,Y) times. This bag receives /// the union of the two bags, the other bag is unchanged. /// </summary> /// <remarks> /// <para>The union of two bags is computed in time O(M+N), where M and N are the size of the /// two bags.</para> /// </remarks> /// <param name="otherBag">Bag to union with.</param> /// <exception cref="InvalidOperationException">This bag and <paramref name="otherBag"/> don't use the same method for comparing items.</exception> public void UnionWith(Bag <T> otherBag) { CheckConsistentComparison(otherBag); if (otherBag == this) { return; // Nothing to do } // Enumerate each of the items in the other bag. Add items that need to be // added to this bag. foreach (var item in otherBag.DistinctItems()) { int copiesInThis = NumberOfCopies(item); int copiesInOther = otherBag.NumberOfCopies(item); if (copiesInOther > copiesInThis) { ChangeNumberOfCopies(item, copiesInOther); } } }
/// <summary> /// Computes the symmetric difference of this bag with another bag. The symmetric difference of two bags /// is all items that appear in either of the bags, but not both. If an item appears X times in one bag, /// and Y times in the other bag, the symmetric difference contains the item AbsoluteValue(X - Y) times. This bag receives /// the symmetric difference of the two bags; the other bag is unchanged. /// </summary> /// <remarks> /// <para>The symmetric difference of two bags is computed in time O(M + N), where M is the size of the /// larger bag, and N is the size of the smaller bag.</para> /// </remarks> /// <param name="otherBag">Bag to symmetric difference with.</param> /// <exception cref="InvalidOperationException">This bag and <paramref name="otherBag"/> don't use the same method for comparing items.</exception> public void SymmetricDifferenceWith(Bag <T> otherBag) { CheckConsistentComparison(otherBag); if (this == otherBag) { Clear(); return; } // Enumerate each of the items in the other bag. Add items that need to be // added to this bag. foreach (var item in otherBag.DistinctItems()) { var copiesInThis = NumberOfCopies(item); var copiesInOther = otherBag.NumberOfCopies(item); var copies = Math.Abs(copiesInThis - copiesInOther); if (copies != copiesInThis) { ChangeNumberOfCopies(item, copies); } } }
public void NumberOfCopies() { var bag1 = new Bag <string>(StringComparer.InvariantCultureIgnoreCase) { null, "hello", "foo" }; Assert.AreEqual(1, bag1.NumberOfCopies("hello")); Assert.AreEqual(1, bag1.NumberOfCopies("FOO")); Assert.AreEqual(1, bag1.NumberOfCopies(null)); bag1.Add(null); bag1.Add("HELLO"); bag1.Add("Hello"); Assert.AreEqual(3, bag1.NumberOfCopies("hello")); Assert.AreEqual(2, bag1.NumberOfCopies(null)); bag1.Remove(null); bag1.Remove(null); Assert.AreEqual(0, bag1.NumberOfCopies(null)); }