views:

43

answers:

2

Hello, I'm trying to use .NET 4's SortedSet<T> collection. It seems to have everything I need minus a couple things.

Q: I want to be able to fetch all elements lower or higher in comparison to a given value. In Java's TreeSet, there are methods named tailSet and headSet, which perform these operations. I'd like to be able to do the same with SortedSet<T>. The closest I can find is GetViewBetween. However, what if I wanted to use SortedSet with string? There is no max value of string that I know of, yet I need to give the method an upper and lower bounds.

How could I mimic the behavior of tailSet and headSet using SortedSet? Considering the implementation of SortedSet, I'd think that these would be very easy methods to implement.

Thanks!

+1  A: 

I think a little LINQ may solve the problem:

        var sortedSet = new SortedSet<string>();
        sortedSet.Add("Santiago");
        sortedSet.Add("Alejandra");
        sortedSet.Add("Carolina");
        sortedSet.Add("Sebastián");

        var head = sortedSet.Where(s => string.Compare(s, "Carolina") < 0);
        var tail = sortedSet.Where(s => string.Compare(s, "Carolina") >= 0);
Edgar Sánchez
+2  A: 

I believe you can emulate them like this: sortedSet.GetViewBetween(start, sortedSet.Max) sortedSet.GetViewBetween(sortedSet.Min, end)

static SortedSet<T> TailSet<T>(this SortedSet<T> set, T start)
{
    return set.GetViewBetween(start, set.Max);
}

static SortedSet<T> HeadSet<T>(this SortedSet<T> set, T end)
{
    return set.GetViewBetween(set.Min, end);
}

Alternately, you can use LINQ:

static SortedSet<T> TailSet<T>(this SortedSet<T> set, T start)
{
    return new SortedSet<T>(set.SkipWhile(
        x => set.Comparer.Compare(x, start) < 0));
}

static SortedSet<T> HeadSet<T>(this SortedSet<T> set, T end)
{
    return new SortedSet<T>(set.TakeWhile(
        x => set.Comparer.Compare(x, end) < 0));
}

The primary difference is that GetViewBetween gives you an object with a pointer to the original set, so any changes in the original set can be reflected in the copies. The LINQ version creates a new set based on the contents of the original, giving copies that don't track each other. Of course, you could also do something like new SortedSet<T>(set.GetViewBetween(set.Min, end)) to get the cloning behavior.

Gabe
For the LINQ approach, you should use the `SortedSet`'s `Comparer` instead of the default. Just in case the set has a custom comparer.
Jeff M
Jeff: Good point. I didn't realize that `Comparer` was a public property.
Gabe
Would the Linq versions iterate over every item in the sorted set while GetViewBetween would use the internal tree structure to fetch the range? I ask because it looks like GetViewBetween would be a O(log n) operation while the Linq equivalent would be O(n)
Polaris878
Polaris878: You are correct in theory, but I think that GetViewBetween counts the nodes in the set, so it too is O(n).
Gabe