C# - defining hashset with custom key - c#

I am using the HashSet and Dictionary in C# to implement a Graph structure. I have a problem with the uniqueness of HashSet elements when the HashSet key is a customized class. Here I have:
public class Point
{
public int x { get; set; }
public int y { get; set; }
}
public class Vertex
{
public Vertex(Point point)
{
VertexLabel = point;
}
public Point VertexLabel { get; private set; }
}
public class Edge
{
public Edge(Vertex to, Vertex from, double weight)
{
FromVertex = from;
ToVertex = to;
Weight = weight;
}
public Vertex FromVertex { get; private set; }
public Vertex ToVertex { get; private set; }
public double Weight { get; private set; }
}
public class Graph
{
public Graph()
{
_Vertexes = new HashSet<Vertex>();
_VertexEdgeMapping = new Dictionary<Vertex, LinkedList<Edge>>();
}
private HashSet<Vertex> _Vertexes;
private Dictionary<Vertex, LinkedList<Edge>> _VertexEdgeMapping;
}
The problem is that when I have same vertexes and I want to add them to the graph, they get duplicated. how can I define a way that the HashSet would understand the uniqueness of my vertexes?

Options:
Override Equals and GetHashCode in Vertex (and probably Point for simplicity), quite possibly implement IEquatable<T> as you go
Create your own implementation of IEqualityComparer<Vertex> and pass that to the constructor of the HashSet<Vertex>
The first option is likely to be the simplest, but I would strongly recommend that you make Point immutable first: mutable types (or types containing mutable types) don't make good hash keys. I'd probably make it a struct, too:
public struct Point : IEquatable<Point>
{
private readonly int x, y;
public int X { get { return x; } }
public int Y { get { return y; } }
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
public override int GetHashCode()
{
return 31 * x + 17 * y; // Or something like that
}
public override bool Equals(object obj)
{
return obj is Point && Equals((Point) obj);
}
public bool Equals(Point p)
{
return x == p.x && y == p.y;
}
// TODO: Consider overloading the == and != operators
}
... then override GetHashCode and Equals and implement IEquatable<> in Vertex too, e.g.
// Note: sealed to avoid oddities around equality and inheritance
public sealed class Vertex : IEquatable<Vertex>
{
public Vertex(Point point)
{
VertexLabel = point;
}
public Point VertexLabel { get; private set; }
public override int GetHashCode()
{
return VertexLabel.GetHashCode();
}
public override bool Equals(object obj)
{
return Equals(obj as Vertex);
}
public bool Equals(Vertex vertex)
{
return vertex != null && vertex.VertexLabel.Equals(VertexLabel);
}
}

Override GetHashCode() and Equals() methods of Vertex class.
Below is example, but you should use a bit better hashing algorithm than mine :)
public class Vertex
{
public Vertex(Point point)
{
VertexLabel = point;
}
public Point VertexLabel { get; private set; }
public override int GetHashCode()
{
return VertexLabel.X + VertexLabel.Y;
}
public override bool Equals(object obj)
{
//your logic for comparing Vertex
}
}

As others have said, override the GetHashCode() of the Vertex class.
Also override the .Equals method. Dictionary will use both GetHashCode and Equals to determine equality.
This is why Dictionary isn't replacing vertices. Vertices with the same coordinates are still fundamentally different as far as the Dictionary is concerned.
I won't pollute your question with yet another source code example as Jon and gzaxx have offered 2 very fine examples already.

Related

How to distinct for a list of list using LINQ?

in my case, I have list of list of points I want to discard the lists of duplicate points using linq in a similar way to how the distinct works in List of items usually.
How could I do it?
Here it is a code snippet to understand better my issue
var points = List<List<Point>>();
public struct Point: IEquatable<Point>
{
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
public int X { get; }
public int Y { get; }
}
Thanks
First, actually implement IEquatable:
public struct Point: IEquatable<Point> {
public Point(int x, int y) {
this.X = x;
this.Y = y;
}
public int X { get; }
public int Y { get; }
public bool Equals (Point other) =>
this.X == other.X && this.Y == other.Y;
}
Then create a custom equality comparer. That requires an equality logic, and a hash code generator. For the equality logic, use SequenceEqual, for the hash code generator, you'll have to play around with it, but here's an example via Jon Skeet. I used part of his logic below:
class ListPointComparer : IEqualityComparer<List<Point>> {
public bool Equals(List<Point> a, List<Point> b) => a.SequenceEqual(b);
public int GetHashCode(List<Point> list) {
int hash = 19;
foreach(var point in list)
hash = hash * 31 + point.GetHashCode();
return hash;
}
}
Now imagine points like this:
var pointsA = new List<Point> { new Point (1,1), new Point(2,2) };
var pointsB = new List<Point> { new Point (1,1), new Point(2,2) };
var pointsC = new List<Point> { new Point (3,3), new Point(4,4) };
var pointLists = new List<List<Point>> { pointsA, pointsB, pointsC };
Use your comparer class:
var results = pointLists.Distinct(new ListPointComparer());
// Outputs only 2 lists, with pointsA and pointsB combined.
You can use HashSet this class provide high-performance set operations. A set is a Collection that CONTAINS NO DUPLICATE elements, and whose elements are in no particular order
Example:
public struct Point
{
public HashSet<int> coordinateX;
public HashSet<int> coordinateY;
public Point(HashSet<int> a, HashSet<int> b)
{
coordinateX = a;
coordinateY = b;
}
}
static void Main(string[] args)
{
var set1 = new HashSet<int>() { 2, 3, 4, 6, 8 };
var set2 = new HashSet<int>() { 67, 31, 1, 3, 5 };
var points = new List<List<Point>>();
points.Add(new List<Point>() { new Point(set1, set2) });
//TODO
}
If you have code like this
public class Point : IEquatable<Point>
{
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
public int X { get; }
public int Y { get; }
public bool Equals(Point other)
{
//Check whether the compared object is null.
if (Object.ReferenceEquals(other, null)) return false;
//Check whether the compared object references the same data.
if (Object.ReferenceEquals(this, other)) return true;
//Check whether the products' properties are equal.
return X.Equals(other.X) && Y.Equals(other.Y);
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public override int GetHashCode()
{
//Get hash code for the Name field if it is not null.
int hashProductX = X == null ? 0 : X.GetHashCode();
//Get hash code for the Code field.
int hashProductY = Y == null ? 0 : Y.GetHashCode();
//Calculate the hash code for the product.
return hashProductX ^ hashProductY;
}
}
then this code would work
var distinct_points = points.Distinct();
assuming points is defined like this
List<Point> points;
you can also use
var distinct_points = points.SelectMany(x => x).Distinct();
if points is defined like this
var points = List<List<Point>>();
documentation this example was adapted from https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinct?view=netframework-4.8
Linq Distinct can use an IEqualityComparer<>
You can implement a new class implementing that interface and then generate distinct lists.
Here is an implementation of a fully coded Point implementing IEquatable<>, and implemented IEqualityComparer<> and a Test class.
The test class does a 'simple' distinct on each list. If you need an more complex distinct, such as distinct points across all lists, post your functional requirements and I can see what i can do.
public struct Point : IEquatable<Point>
{
public Point(int x, int y) : this()
{
X = x;
Y = y;
}
public int X { get; set; }
public int Y { get; set; }
public bool Equals(Point other)
{
if (other.X == X && other.Y == Y)
return true;
return false;
}
public override bool Equals(object obj)
{
if (obj != null && obj.GetType() == typeof(Point))
return Equals((Point)obj);
return base.Equals(obj);
}
public override int GetHashCode()
{
return HashCode.Combine(X, Y);
}
public int GetHashCode(Point obj)
{
return obj.GetHashCode();
}
}
public class PointComparer : IEqualityComparer<Point>
{
public bool Equals(Point x, Point y)
{
return x.Equals(y);
}
public int GetHashCode(Point obj)
{
return obj.GetHashCode();
}
}
public class Tester
{
public static List<List<Point>> Dist(List<List<Point>> points)
{
var results = new List<List<Point>>();
var comparer = new PointComparer();
foreach (var lst in points)
{
results.Add(lst.Distinct(comparer).ToList());
}
return results;
}
}

Make two classes that are dependent on each other equatable

I have class A:
public class A : IEquatable<A>
{
public B Owner { get; set; }
public override bool Equals(object obj)
{
return Equals(obj as A);
}
public bool Equals([AllowNull] A other)
{
return other is A a &&
EqualityComparer<B>.Default.Equals(Owner, a.Owner);
}
}
And I have a class B:
public class B : IEquatable<B>
{
public List<A> Children { get; set; } = new List<A>();
public override bool Equals(object obj)
{
return Equals(obj as B);
}
public bool Equals([AllowNull] B other)
{
return other is B b &&
EqualityComparer<List<A>>.Default.Equals(Children, b.Children);
}
}
The problem I am having is making Equals() methods of the above classes work. The Equals() methods in the example are generated by VS Code, but always return false in case of class B.
I also tried using LINQ expressions (such as SequenceEqual method), but it always results in Stack Overflow (because of circular dependency?).
As a side note, I used .NET Core 3.0 to run this.
So, I managed to find the answer to my question. I just implemented my own custom IEqualityComparer. (in the example below I added public Guid ID property to both classes to do proper GetHashCode()).
public class BComparer : IEqualityComparer<B>
{
public bool Equals([AllowNull] B x, [AllowNull] B y)
{
if (x is null || y is null) {return false;}
if (x.ID == y.ID) {
return x.Children.SequenceEqual(y.Children);
} else {
return false;
}
}
public int GetHashCode([DisallowNull] B obj)
{
return obj.ID.ToString().GetHashCode();
}
}

Check if instance of class exists with certain property

I have a list of classes, each with four properties:
public class BroncoClass
{
public NPC npc { get; set; }
public int TimeLeft { get; set; }
public bool Gravity { get; set; }
public bool Rotation { get; set; }
}
public List<BroncoClass> BroncoList = new List<BroncoClass>();
I want to check if the list contains a class with a specific npc value, for example:
for (int i = 0; i < Main.npc.Length; i++) // For every alive npc
{
if(BroncoList.contains a class where npc == Main.npc[i])
{
}
}
Haven't been able to find an answer online, any help is appreciated.
The real solution is to just keep a collection somewhere and use LINQ to query it. Presumably this collection would be easy to maintain as it would be the collection that is used for all other operations with BroncoClass.
After update to OP...
You already have the list, just use list.Any(o => o.npc == testNpc) or whatever other predicate you may need.
However, if you really want to do the actual question:
Sounds like a reasonable usage of a factory pattern; but you will need to effectively do manual memory management. Your factory would be something like:
// Could be static, but I hate static. Don't use static.
public class BroncoFactory
{
private List<BroncoClass> trackedObjects = new List<BroncoClass>();
public BroncoClass New()
{
var newInstance = new BroncoClass();
trackedObjects.Add(newInstance)
}
// Don't forget to call this or you'll leak!
public void Free(BroncoClass instance)
{
trackedObjects.Remove(instance);
}
public bool ExistsWithNPC(NPC test)
{
return trackedObjects.Any(o => o.npc == test);
}
}
Just really, really don't forget to call Free on an object when you are done with it.
Very similar to #BradleyDotNET's answer. I just folded the factory into the class as static methods. I'm not saying this is right way to go, I'm just offering it as a solution to your question. Using static methods in the class seems closer to what the OP is asking about.
First, I needed an NPC class to get this to compile. Notice that it implements IEquatable so that I can compare instances for equality the way I want to (and that I override GetHashCode because that's a requirement).
public class NPC : IEquatable<NPC>
{
private static int _indexKeeper = 0;
public int Index { get; } = _indexKeeper++;
public bool Equals(NPC other)
{
return Index == other?.Index;
}
public override int GetHashCode()
{
return Index.GetHashCode();
}
}
With that, here's the BroncoClass (mostly untested):
public class BroncoClass
{
private BroncoClass(int timeLeft, bool gravity, bool rotation)
{
Npc = new NPC();
TimeLeft = timeLeft;
Gravity = gravity;
Rotation = rotation;
}
public NPC Npc { get; set; }
public int TimeLeft { get; set; }
public bool Gravity { get; set; }
public bool Rotation { get; set; }
private static List<BroncoClass> _instances = new List<BroncoClass>();
public static BroncoClass Create(int timeLeft, bool gravity, bool rotation)
{
var bronco = new BroncoClass(timeLeft, gravity, rotation);
_instances.Add(bronco);
return bronco;
}
public static bool Remove(NPC npc)
{
var broncoFound = _instances.FirstOrDefault(b => b.Npc == npc);
if (broncoFound == null)
{
return false;
}
_instances.Remove(broncoFound);
return true;
}
public static BroncoClass Find(NPC npc)
{
return _instances.FirstOrDefault(b => b.Npc == npc);
}
}

How to use custom object as dictionary key?

I want to create a Dictionary<Coordinate, Status>, but the key is always equals to "Bot.Core.Games.Coordinate".
Classes
Coordinate
public class Coordinate
{
public int x { get; set; }
public int y { get; set; }
}
Status
public class Enums
{
public enum Status { UNCAPTURED, PLAYER1, PLAYER2, WIN }
}
First try
Dictionary<Coordinate, Status> Fields { get; set; } = new Dictionary<Coordinate, Status>()
{
{new Coordinate() { x = 0, y = 0 }, Status.UNCAPTURED}
}
Second try
I did some research and I found this: Use custom object as Dictionary Key
So the code now looks like this:
public class Coordinate
{
public int x { get; set; }
public int y { get; set; }
public bool Equals(Coordinate coordinate) => coordinate.x.Equals(x) && coordinate.y.Equals(y);
public bool Equals(object o) => Equals(o as Coordinate);
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode();
}
Third try
Since none of the previously tried code works I did more research and found this.So now the code is:
public class Coordinate
{
public int x { get; set; }
public int y { get; set; }
public class CoordinateEqualityComparer : IEqualityComparer<Coordinate>
{
public bool Equals(Coordinate a, Coordinate b) => ((a.x == b.x) & (a.y == b.y));
public int GetHashCode(Coordinate obj)
{
string combined = obj.x + "|" + obj.y;
return (combined.GetHashCode());
}
}
}
Dictionary<Coordinate, Status> Fields { get; set; } = new Dictionary<Coordinate, Status>(new Coordinate.CoordinateEqualityComparer())
{
{new Coordinate() { x = 0, y = 0 }, Status.UNCAPTURED}
}
The key is always "Bot.Core.Games.Coordinate". How to fix this?
You are missing an override in your second try:
public override bool Equals(object o)
The key is always displayed as Bot.Core.Games.Coordinate because in default, the ToString method returns the class name and this is the method the debugger calls to display its value. If you override the method like this:
public override string ToString() => $"{x} / {y}";
It will display its true value.
The problem with your third try was (as was pointed out by Camilo Terevinto and ZorgoZ) your equality comparison - try
public override bool Equals(Coordinate a, Coordinate b)
{
return ((a.x == b.x) && (a.y == b.y));
}
instead

Bidirectional connected between to C# classes

I'm currently working on project (for fun) that involves simulating logic gates. I have a Connection.cs and a Gate.cs that is the parent of other classes like Not, And, Or, etc. In my Gate class I have an abstract method Evaluate that will end up doing the work with inputs and setting outputs.
public abstract class Gate : IConnectable {
private int[] inputs;
private int[] outputs;
protected Gate(int inputCount, int outputCount) {
inputs = new int[inputCount];
outputs = new int[outputCount];
}
...
public abstract void Evaluate();
}
public class Connection {
private IConnectable input;
private IConnectable output;
public Connection(IConnectable from, IConnectable to) {
input = from;
output = to;
}
}
In the end, I am trying to figure out a concise way to have a Gate object contain references to its connections that are inputs/outputs and to have the Connections know what is on either end of the "wire". Is there an easy way to do this?
Generally you want some way to represent a graph. There are many ways to do that.
I would consider a design like this as a starting point:
interface IGate
{
bool Value { get; }
}
class And : IGate
{
public IGate X { get; private set; }
public IGate Y { get; private set; }
public bool Value
{
get
{
return X.Value && Y.Value;
}
}
public And(IGate x, IGate y)
{
X = x;
Y = y;
}
}
class Input : IGate
{
public bool Value { get; set; }
public Input(bool value)
{
Value = value;
}
}
An example is:
new And(new Input(true), new And(new Input(true), new Input(false))).Value
I usually do something like this
public class Node {
private static List<Node> nodes = new List<Node>();
private List<Node> inputs { get; set;}
private List<Node> outputs {get;set;}
protected Node() { }
protected Node(Node input, Node outPut) {
Node newNode = new Node();
nodes.Add(newNode);
newNode.inputs.Add(input);
newNode.outputs.Add(output);
}
}

Categories