[英]Most efficient way to find a range in a sequential javascript array
I have an array of sequential timestamps. 我有一系列连续的时间戳。 I need to grab the subset of the array that falls between a start and end time.
我需要抓住介于开始和结束时间之间的数组子集。 A simplified example would look something like:
一个简化的例子看起来像:
timestamps = [ 5,7,12,13,15,23 ];
startTime = 6;
endTime = 18;
Given the above example, what is the most efficient way of finding the index of the first and last timestamps that fall between the startTime
and endTime
? 鉴于上面的例子,找到
startTime
和endTime
之间的第一个和最后一个时间戳的索引的最有效方法是什么?
A correct script would discover and return indexes 1 & 4 ( timestamps[1], timestamps[4]
) 正确的脚本会发现并返回索引1和4(
timestamps[1], timestamps[4]
)
I could loop through the array and do a comparison, but is there a more efficient way? 我可以遍历数组并进行比较,但是有更有效的方法吗?
(Coffeescript) (CoffeeScript的)
# Search ordered array for timestamps falling between 'start' & 'end'
getRangeBorderIndexes = (stack, start, end) ->
ar = []
ar[0] = getBorder( stack, start, "left" )
ar[1] = getBorder( stack, end, "right" )
return ar
# Use bisection (binary search) to find leftmost or rightmost border indexes
getBorder = (stack, value, side ) ->
mod1 = if side == "left" then 0 else -1
mod2 = if side == "left" then 1 else 0
startIndex = 0
stopIndex = stack.length - 1
middle = Math.floor( (stopIndex+startIndex)/2 )
while stack[middle] != value && startIndex < stopIndex
if value < stack[middle]
if value > stack[middle - 1] then return middle + mod1
stopIndex = middle - 1
else if value > stack[middle]
if value < stack[middle + 1] then return middle + mod2
startIndex = middle + 1
middle = Math.floor( (stopIndex+startIndex)/2 )
return if stack[middle] != value then -1 else middle
timestamps = [ 5,7,12,13,15,23 ]
startTime = 6
endTime = 18
getRangeBorderIndexes( timestamps, startTime, endTime) # returns [1,5]
@kennebec and @Shanimal gave great responses, especially if you are wanting a super simple method for grabbing a subset of an array. @kennebec和@Shanimal给出了很好的回应,特别是如果你想要一个超级简单的方法来获取数组的子集。 However I needed indexes of the sub array rather than the entire sub array.
但是我需要子数组的索引而不是整个子数组。 I did some testing, and the above example consistently takes about 7ms to find the borders of the sub array, even on an array with 10 million entries!
我做了一些测试,上面的例子一直需要大约7ms才能找到子数组的边界,即使在一个有1000万个条目的数组上也是如此!
Thanks to @voithos for pointing me in the right direction. 感谢@voithos指出我正确的方向。 I also modified this code to create the solution above.
我还修改了这段代码来创建上面的解决方案。
Using the lodash / underscore library: 使用lodash /下划线库:
_.select(timestamps,function(i){
return i>=startTime && i<=endTime;
})
Looping is efficient, but Array.filter is easier- 循环是有效的,但Array.filter更容易 -
var timestamps = [ 5,7,12,13,15,23 ],
startTime = 6,
endTime = 18;
var selected=timestamps.filter(function(itm){
return itm>=startTime && itm<=endTime;
});
/* returned value: (Array) 7,12,13,15 */ / *返回值:(数组)7,12,13,15 * /
// filter is built into most browsers, but if you need to support IE before #9 you can shim it: //过滤器内置于大多数浏览器中,但如果您需要在#9之前支持IE,则可以对其进行填充:
if(!Array.prototype.filter){
Array.prototype.filter= function(fun, scope){
var T= this, A= [], i= 0, itm, L= T.length;
if(typeof fun== 'function'){
while(i<L){
if(i in T){
itm= T[i];
if(fun.call(scope, itm, i, T)) A[A.length]= itm;
}
++i;
}
}
return A;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.