2

I am trying to play around with sorted sets in c# for a custom objects and for some reason, it seems like the sorted sets might not be using the references of the objects to store the data..

In the following code snippet, I use a custom IComparer to rely on the Counts property of the custom class. But for some reason, this seems to affect the add functionality. and the counter.Add(two) line does not make any addition to the set even though it is a different reference and has a different value for two properties.

Am I missing something? Have I got something wrong about how SortedSets are supposed to work in C#?

Code Snippet

    public class SortedStructureTesting
    {
        public void TestingSortedSets()
        {
            SortedSet<CounterSetup> counter = new SortedSet<CounterSetup>(new CompareCounts());

            CounterSetup one = new CounterSetup(1);
            CounterSetup two = new CounterSetup(2);
            CounterSetup three = new CounterSetup(3, 2);

            counter.Add(one);
            counter.Add(two); // Does not work. This value does not get added to the set.
            counter.Add(three);

            var max = counter.Max;
            counter.Remove(max);
            var sec = counter.Max;
            counter.Remove(sec);
        }

        public class CounterSetup
        {
            public static Random random = new Random();
            public CounterSetup(int no, int cnt = 1)
            {
                Number = no;
                Count = cnt;
                Blah = new string(Guid.NewGuid().ToString());
            }

            public int Number { get; private set; }

            public int Count { get; set; }

            public string Blah { get; private set; }
        }

        public class CompareCounts : IComparer<CounterSetup>
        {
            public int Compare(CounterSetup one, CounterSetup two)
            {
                return one.Count.CompareTo(two.Count);
            }
        }
    }

Thanks for taking a look and helping!

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
rmehta
  • 33
  • 6
  • `[Sorted]Set` can't have *two* or more *equal* items. You compare `item`s with respect of `Count`; so `Count` must be distinct. Please, note that `one` and `two` instances have the *same* `Count == 1`, that's why `two` has been ignored (not added) – Dmitry Bychenko Dec 14 '20 at 06:09
  • It looks like SortedSet only takes unique Values for the Sort-Property. – Nikolaus Dec 14 '20 at 06:10
  • Hey @DmitryBychenko, Thanks for etting back to me so quickly! I thought the sorted set would handle uniqueness based on the custom reference of the object while using the sorting property to keep the objects sorted. Is that not possible? – rmehta Dec 14 '20 at 06:16
  • @Nikolaus, yea.. it definitely seems like for some reason, the reference is not used for uniqueness.. Would you, by any chance, know if there is some structure I could use to maintain uniqueness based on one property and sort using another? without, you know, succumbing to creating my own data structure? – rmehta Dec 14 '20 at 06:20
  • @devNull YES! Thank you! – rmehta Dec 14 '20 at 06:25

1 Answers1

2

Well [Sorted]Set can contain distinct items only; i.e. Set can't have two more equal items. You compare item (treat them as equal) with respect of Count: if two items have the same Count they are considered equal. In your code

  CounterSetup one = new CounterSetup(1);         // one.Count == 1
  CounterSetup two = new CounterSetup(2);         // two.Count == 1
  CounterSetup three = new CounterSetup(3, 2);    // three.Count == 2

you have one.Count == two.Count == 1 that's why one and two are equal for the counter sorted set. When you add items, the second (which is two) is ignored:

  counter.Add(one);
  counter.Add(two); // Ignored: there's already an item (one) with the same Count
  counter.Add(three);

If you want separated criteria (one for Equals and the other is for order) you can try good old HashSet which you can represent as ordered with a help of Linq:

  using System.Linq;

  ...

  // Items in counter are unique (based on MyEqualityComparer)
  HashSet<CounterSetup> counter = new HashSet<CounterSetup>(
    new MyEqualityComparer()
  );

  // Now we order counter items by different criterium (here we sort by `Count`)
  var ordered = counter
    .OrderBy(item => item.Count);
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • Hey @Dmitry, I see what you mean.. But that feels very weird.. After all, if we use a HashSet counter = new HashSet(); we have all those 3 objects in there. Is there someway to get all 3 objects in the sorted set (or some other sorted collection ) and still have it sorted by another property? – rmehta Dec 14 '20 at 06:23
  • Hey Dmitry, the latest edit to your post definitely helps me solve my problems! thanks!! – rmehta Dec 14 '20 at 06:26
  • @rmehta: alas, `SortedSet` is RB-Tree (Red Black Tree) and it has to operate with *one* criterium. – Dmitry Bychenko Dec 14 '20 at 06:27
  • Ah! I see.. the red black tree with 1 criterium really explains a lot.. thanks for helping me out at this odd hour! – rmehta Dec 14 '20 at 06:30