<?xml version="1.0" encoding="UTF-8"?>
<code>
  <code>/// &lt;summary&gt;
/// Compares the content of two enumerables for equality. Order
/// of elements does NOT matter. Elements may exist multiple
/// times. &lt;c&gt;null&lt;/c&gt; is both a valid key and value.
/// 
/// O(n). Fast for elements with well distributed hashcode.
/// &lt;/summary&gt;
public static bool ContentEquals&lt;T&gt; (
	this IEnumerable&lt;T&gt; first,
	IEnumerable&lt;T&gt; second,
	IEqualityComparer&lt;T&gt; comparer)
{
	// Declare a dictionary to count the occurence of the items in the collection			
	Dictionary&lt;T, int&gt; itemCounts = new Dictionary&lt;T, int&gt; (comparer);

        // null references are stored here.
	int zero = 0;

	// Increase the count for each occurence of the item in the first collection
	foreach (T item in first) {
		if (item == null) {
			zero++;
		}
		else if (itemCounts.ContainsKey (item)) {
			itemCounts[item]++;
		}
		else {
			itemCounts[item] = 1;
		}
	}

	// Decrease the count for each occurence of the item in the second collection
	foreach (T item in second) {
		if (item == null) {
			zero--;
		}
		else if (itemCounts.ContainsKey (item)) {
			itemCounts[item]--;
		}
		else {
			// There was no occurence of this item in the first collection, thus the collections are not equal
			return false;
		}
	}

	// The count of each item should be 0 if the contents of the collections are equal
	foreach (int value in itemCounts.Values) {
		if (value != 0) {
			return false;
		}
	}
	if (zero != 0) {
		return false;
	}

	// The collections are equal
	return true;
}</code>
  <comment>VS08 grants only a maintainability index of 49, but I found no way to improve this method. I'd be glad if you could point out some ideas.</comment>
  <created-at type="datetime">2009-06-22T07:08:07+00:00</created-at>
  <id type="integer">928</id>
  <language>C#</language>
  <permalink>ienumerable-comparision-extension-method</permalink>
  <refactors-count type="integer">8</refactors-count>
  <title>IEnumerable&lt;&gt; comparision extension method</title>
  <trackback-url></trackback-url>
  <updated-at type="datetime">2009-11-17T13:35:09+00:00</updated-at>
  <user-id type="integer">1419</user-id>
  <refactors type="array">
    <refactor>
      <code>public static bool ContentEquals&lt;T&gt; (
	this IEnumerable&lt;T&gt; first,
	IEnumerable&lt;T&gt; second,
	IEqualityComparer&lt;T&gt; comparer)
{
    return !first.Except(second, comparer).MoveNext();
}</code>
      <code-id type="integer">928</code-id>
      <comment>This doesn't quite answer your question, but why just use something as simple as:
</comment>
      <created-at type="datetime">2009-06-22T09:16:43+00:00</created-at>
      <id type="integer">167054</id>
      <language>C#</language>
      <rating type="integer">0</rating>
      <ratings-count type="integer">0</ratings-count>
      <title>On IEnumerable&lt;&gt; comparision extension method</title>
      <user-id type="integer">1277</user-id>
      <user-name>Ants</user-name>
      <user-website nil="true"></user-website>
    </refactor>
    <refactor>
      <code></code>
      <code-id type="integer">928</code-id>
      <comment>Ants: I think the complexity would increase to O(n*n) that way. Usage of a dictionary seems mandatory.</comment>
      <created-at type="datetime">2009-06-22T09:59:29+00:00</created-at>
      <id type="integer">167095</id>
      <language>C#</language>
      <rating type="integer">0</rating>
      <ratings-count type="integer">0</ratings-count>
      <title>On IEnumerable&lt;&gt; comparision extension method</title>
      <user-id type="integer">1419</user-id>
      <user-name>mafutrct</user-name>
      <user-website></user-website>
    </refactor>
    <refactor>
      <code></code>
      <code-id type="integer">928</code-id>
      <comment>Using Reflector on System.Core, it looks like Enumerable.Except() creates an ExceptIterator that uses an internal Set class that implements a hashtable. The structure is very similar to your implementation above.

Of course, your implementation has the benefit of bailing out early since all you are looking for is boolean, while Except() has to build up the entire Set. :-)</comment>
      <created-at type="datetime">2009-06-22T22:30:03+00:00</created-at>
      <id type="integer">167920</id>
      <language>C#</language>
      <rating type="integer">0</rating>
      <ratings-count type="integer">0</ratings-count>
      <title>On IEnumerable&lt;&gt; comparision extension method</title>
      <user-id type="integer">1277</user-id>
      <user-name>Ants</user-name>
      <user-website nil="true"></user-website>
    </refactor>
    <refactor>
      <code></code>
      <code-id type="integer">928</code-id>
      <comment>That's interesting, the default extensions are really more sophisticated than I imagined. :)

I was just about to run a performance test of your suggestion when I noticed that "This method returns those elements in first that do not appear in second. It does not also return those elements in second that do not appear in first."

I guess this means we'd have to do the Except-comparision twice.... :(

Looking for a workaround, I stumbled upon Enumerable.Distinct, but that method does not work for multiple occurrences of the same item in the list :-\ </comment>
      <created-at type="datetime">2009-06-25T08:45:28+00:00</created-at>
      <id type="integer">171780</id>
      <language>C#</language>
      <rating type="integer">0</rating>
      <ratings-count type="integer">0</ratings-count>
      <title>On IEnumerable&lt;&gt; comparision extension method</title>
      <user-id type="integer">1419</user-id>
      <user-name>mafutrct</user-name>
      <user-website></user-website>
    </refactor>
    <refactor>
      <code>		public static bool ContentEquals&lt;T&gt;(
	this IEnumerable&lt;T&gt; first,
	IEnumerable&lt;T&gt; second,
	IEqualityComparer&lt;T&gt; comparer) where T : class
		{
			// Declare a dictionary to count the occurence of the items in the collection			
			Dictionary&lt;T, int&gt; itemCounts = new Dictionary&lt;T, int&gt;(comparer);

			// null references are stored here.
			int zero = 0;
			var totalFirst = 0;

			// Increase the count for each occurence of the item in the first collection
			foreach (T item in first)
			{
				if (item == null)
				{
					zero++;
				}
				else
				{
					totalFirst++;
					int count;
					itemCounts.TryGetValue(item, out count);
					itemCounts[item] = ++count;
				}
			}

			var totalSecond = 0;
			// Decrease the count for each occurence of the item in the second collection
			foreach (T item in second)
			{
				if (item == null)
				{
					zero--;
				}
				else
				{
					totalSecond++;
					if (totalSecond &gt; totalFirst)
					{
						return false;
					}
					int count;
					if (itemCounts.TryGetValue(item, out count))
					{
						itemCounts[item] = --count;
					}
					else
					{
						return false;
					}
				}
			}

			if (zero != 0)
			{
				return false;
			}

			// The count of each item should be 0 if the contents of the collections are equal
			foreach (int value in itemCounts.Values)
			{
				if (value != 0)
				{
					return false;
				}
			}

			// The collections are equal
			return true;
		}</code>
      <code-id type="integer">928</code-id>
      <comment>I have some suggestions about your code. 
The first thing to do is to constraint T to be a class, because (item == null) will be always false for value types.
After that you can optimize you code by counting the elements in the first sequence and in the second. If the second count becomes greater then the first one (you have two sequences with different length ) - they are different.
Place the cheep check (zero != 0) before iterating on itemCounts.
One last thing I think it will lead to a better performance is to use TryGetValue for the dictionary. Here's the code
:
if (itemCounts.ContainsKey(item))
{
	itemCounts[item]++;
}
else
{
	itemCounts[item] = 1;
}

which is compiled as
if (itemCounts.ContainsKey(item))
{
	itemCounts[item] = itemCounts[item] + 1;
}
else
{
	itemCounts[item] = 1;
}
You always perform the check for the item and setting the value(it's a part of the algorithm). However itemCounts[item]++ (itemCounts[item] = itemCounts[item] + 1) is not that innocent. The indexer get will perform FindKey() (the same as ContainsKey) to get the value or throw an exception if the key is not found. In total it FindKey is called twice ! By changing the code to

int count;
itemCounts.TryGetValue(item, out count);
itemCounts[item] = ++count;

This hidden problem is eliminated.
Here's my proposition 


</comment>
      <created-at type="datetime">2009-06-26T07:51:40+00:00</created-at>
      <id type="integer">174490</id>
      <language>C#</language>
      <rating type="integer">5</rating>
      <ratings-count type="integer">1</ratings-count>
      <title>On IEnumerable&lt;&gt; comparision extension method</title>
      <user-id type="integer">1467</user-id>
      <user-name>petar.petrov.myopenid.com</user-name>
      <user-website nil="true"></user-website>
    </refactor>
    <refactor>
      <code>		/// &lt;summary&gt;
		/// Compares the content of two enumerables for equality. Order
		/// of elements does NOT matter. Elements may exist multiple
		/// times. &lt;c&gt;null&lt;/c&gt; is both a valid key and value.
		/// 
		/// O(n). (?) Fast for elements with well distributed hashcode.
		/// &lt;/summary&gt;
		public static bool ContentEquals&lt;T&gt; (
			this IEnumerable&lt;T&gt; first,
			IEnumerable&lt;T&gt; second,
			IEqualityComparer&lt;T&gt; comparer)
		{
			// Declare a dictionary to count the occurrence of the items in the collection			
			Dictionary&lt;T, int&gt; itemCounts = new Dictionary&lt;T, int&gt; (comparer);

			// null references are stored here.
			int zero = 0;

			// Element count
			int items = 0;

			// Increase the count for each occurrence of the item in the first collection
			foreach (T item in first) {
				if (item == null) {
					zero++;
				}
				else {
					items++;

					int count = 0;
					itemCounts.TryGetValue (item, out count);
					itemCounts[item] = ++count;
				}
			}

			// Decrease the count for each occurrence of the item in the second collection
			foreach (T item in second) {
				if (item == null) {
					zero--;
				}
				else {
					items--;
					if (items &lt; 0) {
						// Mismatching number of elements
						return false;
					}

					int count = 0;
					if (itemCounts.TryGetValue (item, out count)) {
						itemCounts[item] = --count;
					}
					else {
						// There was no occurrence of this item in the first collection, thus the collections are not equal
						return false;
					}
				}
			}

			// Number of elements must match
			if (items != 0) {
				return false;
			}

			// Number of nulls has to be equal
			if (zero != 0) {
				return false;
			}

			// The count of each item should be 0 if the contents of the collections are equal
			foreach (int value in itemCounts.Values) {
				if (value != 0) {
					return false;
				}
			}

			// The collections are equal
			return true;
		}</code>
      <code-id type="integer">928</code-id>
      <comment>Petar: I'm not sure about the 'where T : class' part. Doesn't this prevent usage of the function with IEnumerable&lt;int&gt;? Apart from that I really like your suggestions.

This is the code I'm currently using:</comment>
      <created-at type="datetime">2009-07-06T13:11:02+00:00</created-at>
      <id type="integer">189665</id>
      <language>C#</language>
      <rating type="integer">0</rating>
      <ratings-count type="integer">0</ratings-count>
      <title>On IEnumerable&lt;&gt; comparision extension method</title>
      <user-id type="integer">1419</user-id>
      <user-name>mafutrct</user-name>
      <user-website></user-website>
    </refactor>
    <refactor>
      <code>		public static bool ContentEquals&lt;T&gt;(
	this IEnumerable&lt;T&gt; first,
	IEnumerable&lt;T&gt; second,
	IEqualityComparer&lt;T&gt; comparer)
		{
			var isValueType = typeof(T).IsValueType;
			if (isValueType)
			{
				return ValueTypeContentEquals(comparer, first, second);
			}
			return ReferenceTypeContentEquals(comparer, first, second);
		}

		private static bool ReferenceTypeContentEquals&lt;T&gt;(IEqualityComparer&lt;T&gt; comparer, IEnumerable&lt;T&gt; first, IEnumerable&lt;T&gt; second)
		{
			throw new NotImplementedException();
		}

		private static bool ValueTypeContentEquals&lt;T&gt;(IEqualityComparer&lt;T&gt; comparer, IEnumerable&lt;T&gt; first, IEnumerable&lt;T&gt; second)
		{
			throw new NotImplementedException();
		}</code>
      <code-id type="integer">928</code-id>
      <comment>Yes, you can't use this on IEnumerable&lt;int&gt; but the idea was to eliminate the against null on value types - it's always false ( value types cannot be null ). You can remove the zero counter and the checks in the loops. Doing so you will eliminate first.Count + second.Count checks and some increments/decrements. I think you can get the best version by splitting the code in two private methods for value and reference types equality check. Of course if you want you can stay with your current version it's quite good. </comment>
      <created-at type="datetime">2009-07-06T16:43:58+00:00</created-at>
      <id type="integer">189684</id>
      <language>C#</language>
      <rating type="integer">0</rating>
      <ratings-count type="integer">0</ratings-count>
      <title>On IEnumerable&lt;&gt; comparision extension method</title>
      <user-id type="integer">1467</user-id>
      <user-name>petar.petrov.myopenid.com</user-name>
      <user-website nil="true"></user-website>
    </refactor>
    <refactor>
      <code>return !first.Except(second).Concat(second.Except(first)).Any();</code>
      <code-id type="integer">928</code-id>
      <comment></comment>
      <created-at type="datetime">2009-11-17T13:35:06+00:00</created-at>
      <id type="integer">363688</id>
      <language>C#</language>
      <rating type="integer">0</rating>
      <ratings-count type="integer">0</ratings-count>
      <title>On IEnumerable&lt;&gt; comparision extension method</title>
      <user-id type="integer" nil="true"></user-id>
      <user-name>Fabio Maulo</user-name>
      <user-website>http://fabiomaulo.blogspot.com/</user-website>
    </refactor>
  </refactors>
</code>
