PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Tuesday, July 5, 2022

[FIXED] How to compare records containing collections of records without implementing equality comparisons

 July 05, 2022     .net, c#, c#-9.0, collections, pass-by-reference     No comments   

Issue

C# 9 introduces records, which among other benefits allow for really easy comparison. Is there some way I can take advantage of that functionality to compare a record composed of a collection of other records?

For example:

record Foo
{
    string Name {get; set;}
    List<Bar> Bars {get; set;}
    public Foo(string name, params int[] values)
    {
        Name = name;
        Bars = values.Select(v => new Bar(v)).ToList();
    }
}

record Bar
{
    int Value {get; set;}
    public Bar(int value) => Value = value;
}

Somewhere else in the code:

var foo1 = new Foo("Hi",1,2,3);
var foo2 = new Foo("Hi",1,2,3);

return foo1 == foo2; // I want this to return true

By the way I am not looking for a solution to this specific piece of code. I know I can override the == operator or implement IComparable<Foo>, etc. My goal is to leverage built-in functionality so that I don't have to implement my own methods every time I want to compare a data container composed of a collection of data containers. Is there a way to do that?

Thanks!


Solution

I actually found an ok solution. You can extend List<T> to override Equals and GetHashCode

public class ValueEqualityList<T>:List<T>
{
    private readonly bool _requireMathcingOrder;
    public ValueEqualityList(bool requireMatchingOrder = false) => _requireMathcingOrder = requireMatchingOrder;

    public override bool Equals(object other)
    {
        if (!(other is IEnumerable<T> enumerable)) return false;
        if(!_requireMathcingOrder)return enumerable.ScrambledEquals(this);
        return enumerable.SequenceEqual(this);
    }

    public override int GetHashCode()
    {
        var hashCode = 0;
        foreach (var item in this)
        {
            hashCode ^= item.GetHashCode();
        }

        return hashCode;
    }
}

Foo becomes:

record Foo
{
    string Name {get; set;}
    List<Bar> Bars {get; set;}
    public Foo(string name, params int[] values)
    {
        Name = name;

        //this is the line that changed
        Bars = new ValueEqualityList<Bar>(values.Select(v => new Bar(v)));
    }
}

This uses some helper code:

static class EnumerableExtensions
{

    /// <summary>
    /// Returns true if both enumerables contain the same items, regardless of order. O(N*Log(N))
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="first"></param>
    /// <param name="second"></param>
    /// <returns></returns>
    public static bool ScrambledEquals<T>(this IEnumerable<T> first, IEnumerable<T> second)
    {
        var counts = first.GetCounts();

        foreach (var item in second)
        {
            if (!counts.TryGetValue(item, out var count)) return false;
            count -= 1;
            counts[item] = count;
            if (count < 0) return false;
        }

        return counts.Values.All(c => c == 0);
    }


    public static Dictionary<T, int> GetCounts<T>(this IEnumerable<T> enumerable)
    {

        var counts = new Dictionary<T, int>();
        foreach (var item in enumerable)
        {
            if (!counts.TryGetValue(item, out var count))
            {
                count = 0;
            }

            count++;
            counts[item] = count;
        }

        return counts;
    }

}


Answered By - Nigel
Answer Checked By - Robin (PHPFixing Admin)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing