Skip to content

Instantly share code, notes, and snippets.

@shimondoodkin
Last active August 29, 2015 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shimondoodkin/f274d6e17c66a8b72779 to your computer and use it in GitHub Desktop.
Save shimondoodkin/f274d6e17c66a8b72779 to your computer and use it in GitHub Desktop.
rolling/running min in readable javascript
// this grown up to a module -
// https://github.com/shimondoodkin/efficient-rolling-stats
//rolling min max in minified javascript
// from http://stackoverflow.com/a/12195098/466363
// https://gist.github.com/shimondoodkin/f274d6e17c66a8b72779
function RollingMin(e){function s(e){if(t.length!==0&&t[0]<=r-i){t.shift();n.shift()}while(n.length!==0&&n[n.length-1]>e){t.pop();n.pop()}t.push(r);n.push(e);r++;return n[0]}var t=[],n=[],r=0,i=e;return s}
function RollingMax(e){function s(e){if(t.length!==0&&t[0]<=r-i){t.shift();n.shift()}while(n.length!==0&&n[n.length-1]<e){t.pop();n.pop()}t.push(r);n.push(e);r++;return n[0]}var t=[],n=[],r=0,i=e;return s}
function RollingMinIndex(e){function i(e,i){if(t.length!==0&&t[0]<=i-r){t.shift();n.shift()}while(n.length!==0&&n[n.length-1]>e){t.pop();n.pop()}t.push(i);n.push(e);return n[0]}var t=[],n=[],r=e;return i}
function RollingMaxIndex(e){function i(e,i){if(t.length!==0&&t[0]<=i-r){t.shift();n.shift()}while(n.length!==0&&n[n.length-1]<e){t.pop();n.pop()}t.push(i);n.push(e);return n[0]}var t=[],n=[],r=e;return i}
//rolling min max in probably fast javascript, if you treat javascript as c it is fast as c, i.e. no object arrays
// from http://stackoverflow.com/a/12195098/466363
// https://gist.github.com/shimondoodkin/f274d6e17c66a8b72779
function RollingMin(WindowSize)// generator
{
var DequeIndex=[],DequeValue=[],CurrentIndex=0,T=WindowSize;
function atEveryStepDo(CurrentValue)
{
if ( DequeIndex.length!==0 && DequeIndex[0] <= CurrentIndex - T )
{
DequeIndex.shift();
DequeValue.shift();
}
//Head is too old, it is leaving the window
while ( DequeValue.length!==0 && DequeValue[DequeValue.length-1] > CurrentValue )
{
DequeIndex.pop();
DequeValue.pop();
}
//remove elements that have no chance to become minimum in the window
DequeIndex.push(CurrentIndex);
DequeValue.push(CurrentValue);
CurrentIndex++;
return DequeValue[0] //Head value is minimum in the current window
}
return atEveryStepDo;
}
function RollingMax(WindowSize)// generator
{
var DequeIndex=[],DequeValue=[],CurrentIndex=0,T=WindowSize;
function atEveryStepDo(CurrentValue)
{
if ( DequeIndex.length!==0 && DequeIndex[0] <= CurrentIndex - T )
{
DequeIndex.shift();
DequeValue.shift();
}
//Head is too old, it is leaving the window
while ( DequeValue.length!==0 && DequeValue[DequeValue.length-1] < CurrentValue )
{
DequeIndex.pop();
DequeValue.pop();
}
//remove elements that have no chance to become maxbimum in the window
DequeIndex.push(CurrentIndex);
DequeValue.push(CurrentValue);
CurrentIndex++;
return DequeValue[0] //Head value is maximum in the current window
}
return atEveryStepDo;
}
function RollingMinIndex(WindowSize)// generator
{
var DequeIndex=[],DequeValue=[],T=WindowSize;
function atEveryStepDo(CurrentValue,CurrentIndex)
{
if ( DequeIndex.length!==0 && DequeIndex[0] <= CurrentIndex - T )
{
DequeIndex.shift();
DequeValue.shift();
}
//Head is too old, it is leaving the window
while ( DequeValue.length!==0 && DequeValue[DequeValue.length-1] > CurrentValue )
{
DequeIndex.pop();
DequeValue.pop();
}
//remove elements that have no chance to become minimum in the window
DequeIndex.push(CurrentIndex);
DequeValue.push(CurrentValue);
return DequeValue[0] //Head value is minimum in the current window
}
return atEveryStepDo;
}
function RollingMaxIndex(WindowSize)// generator
{
var DequeIndex=[],DequeValue=[],T=WindowSize;
function atEveryStepDo(CurrentValue,CurrentIndex)
{
if ( DequeIndex.length!==0 && DequeIndex[0] <= CurrentIndex - T )
{
DequeIndex.shift();
DequeValue.shift();
}
//Head is too old, it is leaving the window
while ( DequeValue.length!==0 && DequeValue[DequeValue.length-1] < CurrentValue )
{
DequeIndex.pop();
DequeValue.pop();
}
//remove elements that have no chance to become maxbimum in the window
DequeIndex.push(CurrentIndex);
DequeValue.push(CurrentValue);
return DequeValue[0] //Head value is maximum in the current window
}
return atEveryStepDo;
}
/*
example:
min=RollingMin(4);// use generator
> min(3)
3
> min(3)
3
> min(3)
3
> min(2)
2
> min(4)
2
> min(4)
2
> min(4)
2
> min(4)
4
>
max=RollingMax(4);// use generator
max(1)
1
> max(1)
1
> max(3)
3
> max(2)
3
> max(2)
3
> max(2)
3
> max(2)
2
>
mint=RollingMinIndex(4000);// min values of last 4 seconds
> mint(3,new Date().getTime()+ 0);
3
> mint(4,new Date().getTime()+1000);
3
> mint(3,new Date().getTime()+2000);
3
> mint(5,new Date().getTime()+5000);
3
> mint(6,new Date().getTime()+10000);
5
> mint(7,new Date().getTime()+20000);
6
> mint(8,new Date().getTime()+30000);
7
*/
//rolling min max in readable javascript
// from http://stackoverflow.com/a/12195098/466363
Object.defineProperty(Array.prototype, 'Empty', { get: function() { return this.length==0}, enumerable: false, configurable: true });
Object.defineProperty(Array.prototype, 'Head', { get: function() { return this[0]}, enumerable: false, configurable: true });
Object.defineProperty(Array.prototype, 'Tail', { get: function() { return this[this.length-1]}, enumerable: false, configurable: true });
Object.defineProperty(Array.prototype, 'AddTail', { value: function(Value, Index) { return this.push({Value:Value, Index:Index})}, enumerable: false, configurable: true });
Object.defineProperty(Array.prototype, 'ExtractHead', { get: function() { return this.shift()}, enumerable: false, configurable: true });
Object.defineProperty(Array.prototype, 'ExtractTail', { get: function() { return this.pop()}, enumerable: false, configurable: true });
function RollingMin(WindowSize)// generator
{
var Deque=[],CurrentIndex=0,T=WindowSize;
function atEveryStepDo(CurrentValue)
{
if ( (!Deque.Empty) && (Deque.Head.Index <= CurrentIndex - T) )
Deque.ExtractHead;
//Head is too old, it is leaving the window
while ( (!Deque.Empty) && (Deque.Tail.Value > CurrentValue) )
Deque.ExtractTail;
//remove elements that have no chance to become minimum in the window
Deque.AddTail(CurrentValue, CurrentIndex);
var CurrentMin = Deque.Head.Value
//Head value is minimum in the current window
CurrentIndex++;
//atEveryStepDo.min=CurrentMin;
return CurrentMin;
}
return atEveryStepDo;
}
function RollingMax(WindowSize)// generator
{
var Deque=[],CurrentIndex=0,T=WindowSize;
function atEveryStepDo(CurrentValue)
{
if ( (!Deque.Empty) && (Deque.Head.Index <= CurrentIndex - T) )
Deque.ExtractHead;
//Head is too old, it is leaving the window
while ( (!Deque.Empty) && (Deque.Tail.Value < CurrentValue) )
Deque.ExtractTail;
//remove elements that have no chance to become maximum in the window
Deque.AddTail(CurrentValue, CurrentIndex);
var CurrentMax = Deque.Head.Value
//Head value is maximum in the current window
CurrentIndex++;
//atEveryStepDo.max=CurrentMax;
return CurrentMax;
}
return atEveryStepDo;
}
function RollingMinIndex(WindowSize)// generator, //Inedex is useful for time, than windwos size is miliseconds max offset
{
var Deque=[],T=WindowSize;
function atEveryStepDo(CurrentValue,CurrentIndex)
{
if ( (!Deque.Empty) && (Deque.Head.Index <= CurrentIndex - T) )
Deque.ExtractHead;
//Head is too old, it is leaving the window
while ( (!Deque.Empty) && (Deque.Tail.Value > CurrentValue) )
Deque.ExtractTail;
//remove elements that have no chance to become minimum in the window
Deque.AddTail(CurrentValue, CurrentIndex);
var CurrentMin = Deque.Head.Value
//Head value is minimum in the current window
//atEveryStepDo.min=CurrentMin;
return CurrentMin;
}
return atEveryStepDo;
}
function RollingMaxIndex(WindowSize)// generator
{
var Deque=[],T=WindowSize;
function atEveryStepDo(CurrentValue,CurrentIndex)
{
if ( (!Deque.Empty) && (Deque.Head.Index <= CurrentIndex - T) )
Deque.ExtractHead;
//Head is too old, it is leaving the window
while ( (!Deque.Empty) && (Deque.Tail.Value < CurrentValue) )
Deque.ExtractTail;
//remove elements that have no chance to become maximum in the window
Deque.AddTail(CurrentValue, CurrentIndex);
var CurrentMax = Deque.Head.Value
//Head value is maximum in the current window
//atEveryStepDo.max=CurrentMax;
return CurrentMax;
}
return atEveryStepDo;
}
/*
example:
min=RollingMin(4);// use generator
> min(3)
3
> min(3)
3
> min(3)
3
> min(2)
2
> min(4)
2
> min(4)
2
> min(4)
2
> min(4)
4
>
max=RollingMax(4);// use generator
max(1)
1
> max(1)
1
> max(3)
3
> max(2)
3
> max(2)
3
> max(2)
3
> max(2)
2
>
mint=RollingMinIndex(4000);// min values of last 4 seconds
> mint(3,new Date().getTime()+ 0);
3
> mint(4,new Date().getTime()+1000);
3
> mint(3,new Date().getTime()+2000);
3
> mint(5,new Date().getTime()+5000);
3
> mint(6,new Date().getTime()+10000);
5
> mint(7,new Date().getTime()+20000);
6
> mint(8,new Date().getTime()+30000);
7
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment