views:

278

answers:

5

I have a baseclass Event with a DateTime member TimeStamp. Lots of other event-classes will derive from this.

I want to be able to search a list of events fast, so I'd like to use a binary search.

(The list-data is sorted on timestamp, but there might be duplicate timestamps for events that occurred simultaneously)

So I started out writing something like this :

public class EventList<T> : List<T> where T : Event
{
   private IComparer<T> comparer = (x, y) => Comparer<DateTime>.Default.Compare(x.TimeStamp, y.TimeStamp);

   public IEnumerable<T> EventsBetween(DateTime inFromTime, DateTime inToTime)
   {
       // Find the index for the beginning. 
       int index = this.BinarySearch(inFromTime, comparer);

       // BLAH REST OF IMPLEMENTATION
   }
}

The problem is that the BinarySearch only accepts T (so - an Event type) as parameter, while I want to search based on a member of T - the TimeStamp.

What would be a good way to approach this ?

+1  A: 

I think that you already are on the right way with your comparer function. It compares two T's by comparing the dates of them.

To handle the inFromTime parameter to BinarySearch you can create a dummy Event which has the correct TimeStamp and pass that dummy to BinarySearch.

Also, just to make sure: Is the list sorted on the time field? Otherwise binarysearch won't work.

Edit

This problem is more complex than I first thought. A solution that would help you is:

  • Make an adapter class which exposes your EventList as an IList.
  • Use a BinarySearch extension method on IList to do the search.

Unfortunately there is no built in BinarySearch extension method, so you will have to write your own. In case you write your own search it might not be worth the extra effort to put it in an extension method. In that case just implementing a custom BinarySearch algorithm yourself in your EventList class is probably the best you can do.

Another option would be if there was a form of BinarySearch that accepted a delegate that extracts the relevant key from T, but that is not available either.

Anders Abel
The problem is that BinarySearch doesn't take a DateTime as first parameter, but expects an object of Type T (so Event-derived) !
Pygmy
See my update on a dummy Event instance.
Anders Abel
That won't work.int index = this.BinarySearch(new Event(inFromTime), comparer);doesn't work since BinarySearch expects a first parameter of type T which can be different than (but derived from) GameEvent.I can't use new T(inFromTime) since the derived classes do not support a constructor with only a parameter timestamp.
Pygmy
See my added thoughts under the "Edit" heading. This problem looks very simple at first sight, but in reality it isn't.
Anders Abel
A: 

The easiest way is to define a small helper class which implements IComparer<T>.

public class CompUtil : IComparer<T> {
  public int Compare(T left, T right) { 
    return left.TimeStamp.CompareTo(right.TimeStamp);
  }
}

You can then use it as follows

int index = this.BinarySearch(inFromTime, new CompUtil());
JaredPar
The problem is that BinarySearch doesn't take a DateTime as first parameter, but expects an object of Type T (so Event-derived) !
Pygmy
A: 

If your Event class contains the property you want to sort on, your approach will be fine. The compiler can then verify that whatever T is being passed in, it will inherit from Event and contain the DateTime property. If Event does not contain the DateTime property, you would probably want to add it to event, or constrain T to be a more specific type, which contains the property needed for your search.

Remember to make sure your list is sorted before applying BinarySearch.

driis
The list is sorted, the problem is the first parameter of the BinarySearch method...
Pygmy
A: 
public class EventList<TEvent, TData>
   : List<TEvent> where TEvent : Event, TData: DataTime
{
   class Comparer : IComparer<TData> { } // as JaredPar mentioned above

   public IEnumerable<TEvent> EventsBetween(TData from, TData to) { }
}
abatishchev
A: 

Maybe you could consider using SortedList as base class instead of List. You could then use IndexOfKey method to search for a specified TimeStamp. That method does a binary search.

Mikael Sundberg
SortedList doesn't allow for duplicate keys.
Pygmy