views:

343

answers:

6

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 Paid(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)
+4  A: 

Have you looked at SortedDictionary or SortedList?

Vadim
For a second I thought I must have been going blind. One problem though, neither support duplicate keys, which is a requirement.
Matthew Scharley
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
I'd much prefer using LINQ over manually overriding equals...
RCIX
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
Think of what I need as a SortedQueue class. That analogy actually works really well.
Matthew Scharley
RCIX: Each to his own right. I personally hate LINQ.
Noon Silk
@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
A: 

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
A: 

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.

RCIX
+5  A: 

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
See "Priority queue in .Net", http://stackoverflow.com/questions/102398/priority-queue-in-net
dangph
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
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
+1  A: 

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
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
+1  A: 

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