DeepEquals but ignoring order of properties?

Apr 19, 2010 at 4:28 PM

I'd like to use DeepEquals to compare two JObject trees, but it looks like this uses JContainer.ContentsEqual, which just loops through the child tokens in whatever order they are stored, and so will be sensitive to differences in property ordering.

In JavaScript the order of an object's properties is unpredictable, so logically these two are the same:

{ "firstName": "blah", "lastName": "blah" }

{ "lastName": "blah", "firstName": "blah" }

Is there an easy way to do a deep comparison such that the order of properties is not treated as significant?

Apr 19, 2010 at 4:42 PM

PS. I'm currently using:

private static bool DeepEqualsUnordered(JToken left, JToken right)
{
    if (left.Type != right.Type)
        return false;

    if (left.Type == JTokenType.Array)
    {
        var l = left.Children().GetEnumerator();
        var r = right.Children().GetEnumerator();

        while (l.MoveNext())
        {
            if (!r.MoveNext())
                return false;

            if (!DeepEqualsUnordered(l.Current, r.Current))
                return false;
        }

        return !r.MoveNext();
    }

    if (left.Type == JTokenType.Object)
    {
        var l = ((IDictionary<string, JToken>) left).OrderBy(p => p.Key).GetEnumerator();
        var r = ((IDictionary<string, JToken>) right).OrderBy(p => p.Key).GetEnumerator();

        while (l.MoveNext())
        {
            if (!r.MoveNext())
                return false;

            if (l.Current.Key != r.Current.Key)
                return false;

            if (!DeepEqualsUnordered(l.Current.Value, r.Current.Value))
                return false;
        }

        return !r.MoveNext();
    }

    return JToken.DeepEquals(left, right);
}

Coordinator
Apr 20, 2010 at 8:15 AM

If order is important you could order the properties before comparing?

Oct 17, 2011 at 3:34 PM

I agree with danielearwicker. I was surprised that DeepEquals respects the order of properties. An option or separate method that ignores property order would be very desirable.

Apr 16, 2015 at 9:28 AM
Edited Apr 17, 2015 at 11:33 AM
This is an old topic, but in case someone finds this on google:

If you want to ignore the order of elements in a JArray, then you can change the body of the "if (left.Type == JTokenType.Array)" branch to:
var l = left.Children().AsSequence();
var r = right.Children().AsSequence();

if (l.Count != r.Count)
    return false;

var rPermutations = r.Permutations();

// Both arrays are equivalent if and only if the right array
// is an exact match of at least one permutation of the right array.
return rPermutations.Any(
    permutation => l.Zip(permutation)
                    .All(pair => DeepEqualsUnordered(pair.Item1, pair.Item2)));
Note: I'm using Sequences to calculate the permutations, but you could also use the LINQ Extension Library


Update: Turns out I had been misinformed - two arrays with the same elements in different order are considered to be different by the JSON spec.