3

I'm wondering how can I change way in which SortedSet determines whether two objects are equal.

I have SortedSet<Tuple<Edge, int>>(new Helpers.EdgeDistanceComparer()) and Comparer method is:

public class EdgeDistanceComparer : IComparer<Tuple<Edge,int>>
{
    public int Compare(Tuple<Edge, int> x, Tuple<Edge, int> y)
    {
        return Comparer.Default.Compare(x.Item2, y.Item2);
    }
}

I believe because of this Sorted set compares only integers (Tuple.Item2), how can I do comparison on Edge class

EDIT

To explain question more:

I want to compare items by Edge class, and to sort them by Tuple.Item2, and if two Tuple.Item2 are equal, I want to add that item to SortedSet, nevertheless.

EDIT 2

Ben Gave good answer but in the end I've decided to add one more property to my class so that value I kept in Tuple.Item2 is now being saved inside property of my Edge class. And then I implemented IComparable interface, so here is how my Edge class looks like:

public class Edge : IComparable
{
    public Coordinate Coordinates { get; set; }
    public string Value { get; set; }
    public Edge Parent { get; set; }
    public int Cost { get; set; }


    public int CompareTo(object obj)
    {
        var thatEdge = (Edge) obj;
        if (Cost > thatEdge.Cost)
        {
            return 1;
        }
        if (Cost < thatEdge.Cost)
        {
            return -1;
        }
        // cost may be same but coordinates must be different
        if (Cost == thatEdge.Cost &&
            (Coordinates.X != thatEdge.Coordinates.X || Coordinates.Y != thatEdge.Coordinates.Y))
        {
            return -1;
        }
        return 0;
    }
}

And IComparer for SortedSet:

   public class EdgeDistanceComparer : IComparer<Edge>
    {
        public int Compare(Edge x, Edge y)
        {
            return Comparer.Default.Compare(x, y);
        }

    }
hyperN
  • 2,524
  • 6
  • 49
  • 87

1 Answers1

3

I believe this answer to another question contains the closest thing you'll get to what you want

In this case the TValue is your Tuple<Edge,int>, so your IComparer that's passed in on construction would be the same as the one in your post.

The only other addition, to make it behave like a Set, is to add a check to the Add method to only add to the collection if the collection does not already contain an item with the same Edge. One way to do that would be:

public void Add(TValue item) 
{
    if(!_Container.Select(p => p.Value).Contains(item, _equalityComparer) 
        _Container.Add(Indexed.Create(_Index++, item)); 
}

Where _equalityComparer is an IEqualityComparer<Tuple<Edge,int>> which returns true if the Edges are equal.

This is a bit of a mess unfortunately, and I think it probably loses a lot of performance benefits you probably want from the SortedSet, but it may be the best you can get, since there's nothing in System.Collections geared towards this. If performance isn't important, you could just try a Set or even List, and just sort when you need to. Even if performance is important, you might still want to do a comparison and see if this is even much better.

Community
  • 1
  • 1
Ben Aaronson
  • 6,805
  • 2
  • 21
  • 37