10

I have a need for a fairly specialised collection .NET, and I don't think that the BCL can help me, but I thought I'd throw it out there for if anyone knew of something similar.

Basically, my requirements are thus:

  • I have a list of pairs of values, such as: (3, 10), (5, 10), (3, 7), (5, 5)
  • Order is important, ie. (3, 10) != (10, 3)
  • Duplicates of individual values are fine, but duplicate pairs should be dropped (preferably silently).
  • The kicker is, I need this list sorted all the time. I'm only ever interested in the first value in the list as defined by the sort algorithm at any one time.

So, some example code of what I want to be able to do (as I envision it would probably be implemented, other implementations that fit the above are fine to):

public class Pair
{
    public Pair(int first, int second)
    { First = first; Second = second; }
    public int First { get; set; }
    public int Second { get; set; }
}

SortedQueue<Pair> foo = new SortedQueue<Pair>((left, right) => {
    return right.First - left.First;
});

foo.Add(new Pair(10, 3));
foo.Add(new Pair(4, 6));
foo.Add(new Pair(6, 15));
foo.Add(new Pair(6, 13)); // This shouldn't cause a problem

Pair current = foo.Shift(); // current = (4, 6)
Matthew Scharley
  • 115,776
  • 51
  • 189
  • 215

6 Answers6

12

I quote:

I need this list sorted all the time. I'm only ever interested in the first value in the list as defined by the sort algorithm at any one time.

This sounds like you do not want a Sorted Queue but a Priority Queue. If performance is an issue then a PQ will certainly be faster, O(log n) vs O(n). But the drop-duplicates issue would require you to keep a parallel HashSet<> as well.

Henk Holterman
  • 236,989
  • 28
  • 287
  • 464
  • 6
    See "Priority queue in .Net", http://stackoverflow.com/questions/102398/priority-queue-in-net – dan-gph Sep 19 '09 at 10:37
  • Thankyou for the proper name and link. And now that I look over the wikipedia article, the way I was thinking of implementing it was a blend of the two types listed in the 'simple implementations' (keeping a list with a flag as to whether it was sorted or not, simply append on insert, then sort if needed before retrieval). And thanks dangph for the link to some actual implementations. – Matthew Scharley Sep 19 '09 at 10:47
  • For the record, this was for an implementation of A* search too, which that wikipedia article has some notes on too, so double kudos. – Matthew Scharley Sep 19 '09 at 10:48
  • fyi, a thread safe priority queue implementation can be found here: https://code.msdn.microsoft.com/Samples-for-Parallel-b4b76364/sourcecode?fileId=44488&pathId=1769618430 – JasonS Sep 26 '15 at 00:06
5

Have you looked at SortedDictionary or SortedList?

Vadim
  • 19,585
  • 14
  • 61
  • 100
  • 3
    For a second I thought I must have been going blind. One problem though, neither support duplicate keys, which is a requirement. – Matthew Scharley Sep 19 '09 at 05:34
  • I've got news for you Matt: If you're key is duplicated, it's the same object. The lesson here is to override Equals so that they equal on a basis you set. – Noon Silk Sep 19 '09 at 05:49
  • 1
    My example above doesn't care about keys though, but to use SortedDictionary or SortedList, the only way to do that is to sort on keys. I want to sort on the *values* though. The way that doesn't looks like a horrible hack is to use one value as the key and the other as the value instead of having the `Pair` class described above (which doesn't work for the reason I noted). The other way is to use the `Pair` as the key and null for all the values... – Matthew Scharley Sep 19 '09 at 06:02
  • Think of what I need as a SortedQueue class. That analogy actually works really well. – Matthew Scharley Sep 19 '09 at 06:04
  • @MAtthew Scharley: Then i'd recommend going with my LINQ solution. It lets you sort on whatever criteria you want, and you could build a wrapper class around it that eases the use of it. – RCIX Sep 19 '09 at 06:11
2

Check out the C5 Generic Collections Library which already has an implementation just like you're looking for, called an IntervalHeap or Priority Queue. Here's some documentation on it from the C5 Book: IPriorityQueue<T>

Marcus Griep
  • 7,288
  • 1
  • 20
  • 23
1

There is nothing built into .NET at this time that meets all of your requirements. In .NET 4.0 there is a SortedSet class. I realize that it probably does not do you much good now.

SortedList comes close if you implement IComparable. You would just use the Pair as the key and the value. You would only be storing the reference to your Pair twice so it isn't a huge memory overhead. But this will not take care of duplicates.

There are numerous ways to write it yourself, but nothing built in that fully matches what you need. There are a few open source SortedSet implementations (there is one in Spring.Net for example). That might be your best bet right now.

Mike Two
  • 41,318
  • 7
  • 77
  • 93
  • 1
    After many times of using hashes in Perl/PHP to just get access to a set type, and every time I only use the key's in a collection it feels like a hack and I want to throw up. Unfortuanately, that's what we're stuck with. But! This is a personal project, and I already have VS 2010 installed, so I might just use that after all... – Matthew Scharley Sep 19 '09 at 10:53
0

SortedList would be best, all you have to do then is implement IComparable in your Pair class, and it would auto-order them. As for removing duplicates, I dont think Sorted list handles that, but you could inherit from it, and add this functionality.

Erich
  • 647
  • 5
  • 6
0

you should most likely use a Lookup class as The Skeet mentions in his answer. Then you build and access it with something like this:

List<Lookup<int, int>> yourList = new List<Lookup<int, int>>();
yourList.Add(new Lookup(3,5));
//...
var list = from item in yourList
           orderby list.Key //or whatever sort criteria you want here
           select item;
//use list

The syntax may be a little off in 1 or 2 spots but it ought to work.

Community
  • 1
  • 1
RCIX
  • 35,702
  • 48
  • 141
  • 204