views:

150

answers:

3

I have a sorted dictionary where the key is a date and the value is a integer that represents time left. i have 3 years worth of data

so it would be something like

Key: 2009-1-1, Value: 100
Key: 2009-1-2, Value: 97
Key: 2009-1-3, Value: 92
Key: 2009-1-4, Value: 87 ...
...
Key: 2009-1-30, Value: 0

I would like to calculate average change per day and wanted to see if there way any elegant way of doing this.

+3  A: 

If the values are strictly descending, then the average change per day is:

 total change = difference between time on last day and time on first day
 average change = total change / number of days

The whole thing can be calculated in O(1), provided you know the size of your dictionary.

Avi
how would you get the last element from a sorteddictionary
ooo
This is the average change per day regardless of whether your values are strictly descending or not. The average *absolute* change is another matter, of course.
Dan Tao
@oo: as for getting the last element; you might want to go with `SortedList<TKey, TValue>`, which uses less memory anyway (probably a good thing). A `SortedDictionary<TKey, TValue>` is better for insertion and removal of *unsorted* data; but I suspect that you may be getting your data in sorted order already?
Dan Tao
@Dan: Generally, unless defined otherwise, I understand "daily change" to mean the absolute difference of the two values.
Avi
+1  A: 

How to do it in code...

This will handle increasing and decreasing:

        int changeTot = 0;
        int lastVal = 0;
        bool first = true;

        foreach (int val in myDict.Values)
        {
            if (!first) changeTot += val - lastVal;
            lastVal = val;
            first = false;
        }

        double avg = (double)changeTot / myDict.Count;

Of course this is O(n) since you're only going through the array once.

If your values are only increasing or only decreasing

You can use a bit of Linq:

double avg = (double)(myDict.Last().Value - myDict.First().Value) / myDict.Count();

This would be O(1)

badbod99
Wouldn't that be O(n), if you're traversing the array once?
hexium
Yep, you're right. corrected
badbod99
It'll be faster if you avoid the !first test (and first = false assignment) every time. Which you can do by initializing lastVal to -myDict.First().Value.
Emil
Yep, true. But then .First is a linq extended method. Would need to test the performance of that, since setting a bool to false is setting 1 bit. I suspect the above would be faster on anything but massive data sets
badbod99
A: 

Are you doing this more than once? You could keep track of the average change, and every time you insert, remove, or alter an element in the dictionary, you could update the average change just by looking at the element's two neighbors.

Mike Dunlavey