Development on a Shoestring

Comparing two arrays (or IEnumerables) in C#

Much to my surprise I found that .NET 3.5 doesn’t seem to have a native method for comparing two arrays or collections of any type.  The LINQ extension methods offer a whole lot of added functionality for IEnumerable<T> collections, but not native comparison.  The Equals method is still the base object.Equals method that does a reference equality (i.e. Are these two the same object?) not a value equality (do they contain the same values?)

So, finding myself needing an equality comparison between two arrays, I’ve written the following extension method:

   1: /// <summary>
   2: /// Checks whether a collection is the same as another collection
   3: /// </summary>
   4: /// <param name=”value”>The current instance object</param>
   5: /// <param name=”compareList”>The collection to compare with</param>
   6: /// <param name=”comparer”>The comparer object to use to compare each item in the collection.  If null uses EqualityComparer(T).Default</param>
   7: /// <returns>True if the two collections contain all the same items in the same order</returns>
   8: public static bool IsEqualTo<TSource>(this IEnumerable<TSource> value, IEnumerable<TSource> compareList, IEqualityComparer<TSource> comparer)
   9: {
  10:     if (value == compareList)
  11:     {
  12:         return true;
  13:     }
  14:     else if (value == null || compareList == null)
  15:     {
  16:         return false;
  17:     }
  18:     else
  19:     {
  20:         if (comparer == null)
  21:         {
  22:             comparer = EqualityComparer<TSource>.Default;
  23:         }
  24:  
  25:         IEnumerator<TSource> enumerator1 = value.GetEnumerator();
  26:         IEnumerator<TSource> enumerator2 = compareList.GetEnumerator();
  27:  
  28:         bool enum1HasValue = enumerator1.MoveNext();
  29:         bool enum2HasValue = enumerator2.MoveNext();
  30:  
  31:         try
  32:         {
  33:             while (enum1HasValue && enum2HasValue)
  34:             {
  35:                 if (!comparer.Equals(enumerator1.Current, enumerator2.Current))
  36:                 {
  37:                     return false;
  38:                 }
  39:  
  40:                 enum1HasValue = enumerator1.MoveNext();
  41:                 enum2HasValue = enumerator2.MoveNext();
  42:             }
  43:  
  44:             return !(enum1HasValue || enum2HasValue);
  45:         }
  46:         finally
  47:         {
  48:             if (enumerator1 != null) enumerator1.Dispose();
  49:             if (enumerator2 != null) enumerator2.Dispose();
  50:         }
  51:     }
  52: }
  53:  
  54: public static bool IsEqualTo<TSource>(this IEnumerable<TSource> value, IEnumerable<TSource> compareList)
  55: {
  56:     return IsEqualTo(value, compareList, null);
  57: }
  58:  
  59: public static bool IsEqualTo(this IEnumerable value, IEnumerable compareList)
  60: {
  61:     return IsEqualTo<object>(value.OfType<object>(), compareList.OfType<object>());
  62: }

Updated: Jugen (see comment below) made some quality suggestions that I’ve used to improve the code here.  To see the state of the code when the comment was made, see here.

It gives you an extension methods on any collection that implements IEnumerable<T>.  There is an optional parameter of type IEqualityComparer<TSource> which if not null will be used to compare each item in the collections.  Otherwise it will use the default comparer for TSource. It will also work for untyped IEnumerable collections, the overloaded method passes the collections through to the IsEqualTo<TSource> method with object as the TSource.  This is really just there for backwards compatibility.

As far as speed goes, I ran a test with 2 collections of 10,000,000 (I stopped there because I started getting out of memory exceptions when I was populating the test collections after that!) items & it took 0.89 seconds, so I think that’d do for most scenarios.  If you want to use this code you can grab a copy of it here.

  • 9 Comments
  • Filed under: General, Tags: , ,
  • I already posted this on the tumblelog, but I think it bears repeating: With the next release of Visual Studio, the common .NET assemblies will be provided with source code

    Today I’m excited to announce that we’ll be providing this with the .NET 3.5 and VS 2008 release later this year.

    We’ll begin by offering the source code (with source file comments included) for the .NET Base Class Libraries (System, System.IO, System.Collections, System.Configuration, System.Threading, System.Net, System.Security, System.Runtime, System.Text, etc), ASP.NET (System.Web), Windows Forms (System.Windows.Forms), ADO.NET (System.Data), XML (System.Xml), and WPF (System.Windows).  We’ll then be adding more libraries in the months ahead (including WCF, Workflow, and LINQ).  The source code will be released under the Microsoft Reference License (MS-RL).

    You’ll be able to download the .NET Framework source libraries via a standalone install (allowing you to use any text editor to browse it locally).  We will also provide integrated debugging support of it within VS 2008.

    (more…)

    Nullable types & lazy loading FTW

    Visual Studio 2005 & .NET 2.0 introduced a bunch of new concepts to .NET development, probably the most well known being Generics. One of the possibly less well know & certainly less well understood was the introduction of nullable types, specifically nullable value types. 

    For the uninitiated, I’ve got a very brief intro below.  Here’s a more in-depth article on Nullables.

    Value types (int, long, float, double, etc.) are not able to be set to a null value, they’re set to their default value (for numeric value types this is 0).  To make an int nullable, you append the type with a question mark, i.e. int? This means that you can now do this:

       1:  int? x;
       2:  //Some processing
       3:  if (x == null)
       4:  {
       5:      //Do something
       6:  }

    Actually the nullable type wrapper gives you a more elegant way of checking for null with the HasValue property. All nullable types have this property & if the object is not null it will be true.  The nullable type specification is actually a bit of syntactic sugar: int? is just a compiler shortcut for the real Nullable type of Nullable<int>.

    Right, nifty, but so what? How do we use this? Well a simple use is when you need to pass through an optional value to a SQL Server stored proc. Previously you’d have to write an overloaded version of the method that didn’t have the optional parameter and just create a null sql parameter for the command. With a nullable int, you can just pass the parameter through as null.

    (more…)

    ReSharper 3.0 released

    JetBrains have released ReSharper 3.0, but I think they may have to re-brand it, as it now has extensive VB.NET support too:

    ReSharper is proud to enable Visual Basic .NET development, providing full support and a host of productivity features. Visual Basic developers will be sure to enjoy a truly enhanced Visual Studio experience thanks to ReSharper’s quick navigation and search, all the important code refactorings, full-fledged code assistance, code completion & generation, code templates, and a lot more.

    Maybe they can call it ReCLR or ReNetter or something like that…

    .NET the C# way

    Brian Madsen has launched the CSharpZealot site, a new C# community site. 

    The CSharpZealot community is focused on working with Microsoft Visual C# for the .Net framework and supporting technologies.

    The reason for this community is to share the knowledge of the masses and to bring technical articles and news to the community.

    Check it out if you do C# development, and get involved.  There’s an Orcas CTP Forum too if you’ve managed to download all 7gig of it.

  • Filed under: General, Tags: ,