Collection equality regardless of item order

3 12 2004

I wanted to test collection equality disregarding order. One int array of 1,2,3,4 and another of 4,2,3,1 would be equal. Also, collections of collections would be compared only by their items and the number of times those items appear in any collection.

char[] charsA = new char[] { 'a', 'b', 'c', 'a' };
char[] charsB = new char[] { 'a', 'c', 'b', 'a' };
Assert.IsTrue(Collection.Equals(charsA, charsB, false));
int[] intA = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 };
int[] intB = new int[] { 9, 8, 7, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0 };
Assert.IsTrue(Collection.Equals(intA, intB, false));
ArrayList arrayListA = new ArrayList();
ArrayList arrayListB = new ArrayList();
arrayListA.Add(charsA); // Adds the array as an item
arrayListB.AddRange(charsB); // Adds the items from the array
arrayListA.Add(intA);
arrayListB.AddRange(intB);
Assert.IsTrue(arrayListA.Count == 2);
Assert.IsTrue(arrayListB.Count == 20);
Assert.IsTrue(Collection.Equals(arrayListA, arrayListB, false));

I had to create the RelaxComparer so I could add all types to two SortedList collections that are built by the algorithm to determine equality. The SortedList objects are also used to keep track of the number of times each item appears in each collection.

I merged the CollectionEquals method I created earlier together with this new algorithm to a new Collection class that can test both types of collection equality:

Read the rest of this entry »



RelaxComparer : Missing IComparer?

2 12 2004
5.CompareTo(4); // returns 1 (greater than)
5.CompareTo(5); // returns 0 (equal)
5.CompareTo(6); // returns -1 (less than)

// A class will only compare to its same type.
5.CompareTo(’c'); // Throws ArgumentException

I created the following class to use instead of the default Comparer class (which just calls the CompareTo method of each object implementing IComparable) to perform sorting (and other comparison related algorithms) with objects of different types.

/// <summary>
/// Compares two objects for equivalence, where objects of different
/// types are compared by their string representations.
/// </summary>
public class RelaxComparer : IComparer
{
  public int Compare(object x, object y)
  {
    Type typeX = x.GetType(), typeY = y.GetType();
    /* IComparable.CompareTo(object obj) The parameter, obj, must be
     * the same type as the class or value type that implements this
     * interface; otherwise, an ArgumentException is thrown */
    if (typeX == typeY && typeof(IComparable).IsAssignableFrom(typeX))
      return ((IComparable)x).CompareTo(y);
    else
      return x.ToString().CompareTo(y.ToString()); // use strings
  }
}

So now you can add strings, chars, ints in any order and sort the items with the sort method of ArrayList:

char[] chars = new char[] { 'a', 'd', 'c', 'b' };
int[] ints = new int[] { 4, 3, 1, 2, 0 };
char[] CHARS = new char[] { 'B', 'C', 'D', 'A' };

ArrayList arrayList = new ArrayList();

foreach(char x in chars)
  arrayList.Add(x);

foreach(int x in ints)
  arrayList.Add(x);

foreach(char x in CHARS)
  arrayList.Add(x);

arrayList.Sort(new RelaxComparer());

foreach(object o in arrayList)
  Console.Write(string.Format("{0} ", o));

// output: 0 1 2 3 4 A B C D a b c d


How To Retrieve Column Schema by Using the IDataReader GetSchemaTable Method

1 12 2004

The Microsoft KB example code or class library documentation do not explain how to efficiently return a table’s schema. For example, this code follows the documentation:

DataTable dataTable = null;
using(IDbConnection dbConnection = (IDbConnection)database.Unwrap())
{
  dbConnection.Open();
  using (IDbCommand dbCommand = dbConnection.CreateCommand())
  {
    dbCommand.CommandType = CommandType.Text;
    dbCommand.CommandText = "SELECT * FROM SomeLargeTable;";
    using (IDataReader dataReader =
    dbCommand.ExecuteReader(CommandBehavior.KeyInfo))
    {
      dataTable = dataReader.GetSchemaTable();
      dataReader.Close();
    }
  }
  dbConnection.Close();
}
// look at table schema stored in dataTable

Results in the following SQL executed on Sql Server:

SET FMTONLY OFF; SET NO_BROWSETABLE ON;
SELECT * FROM SomeLargeTable; SET NO_BROWSETABLE OFF;

If you add “| CommandBehavior.SchemaOnly” to the ExecuteReader method call:

SET FMTONLY OFF; SET NO_BROWSETABLE ON; SET FMTONLY ON;
SELECT * FROM SomeLargeTable; SET FMTONLY OFF; SET NO_BROWSETABLE OFF;

In the SqlDataReader implementation, the CommandBehavior.SchemaOnly sets FMTONLY ON which, according to the Transact-SQL Reference, “No rows are processed or sent to the client as a result of the request when SET FMTONLY is turned ON.” With (CommandBehavior.KeyInfo | CommandBehavior.SchemaOnly), I had a significant preformance increase - makes perfect sense since returning 100,000,000 rows to retrieve table schema is inefficent, to say the least.