我有一个在java脚本中按升序排序的数组,其中包含以毫秒为单位的日期。
// Sample data; This may grow upto 1k or 2k
var dates = [1333391400000,1335292200000,1335810600000,1336329000000,1336933800000,1337020200000,
1337193000000,1337538600000,1337625000000,1337797800000,1338316200000,1338921000000,
1339093800000,1339439400000,1340303400000,1341772200000,1342463400000,1343068200000];
我没有开始和结束索引。我有价值观。我需要从java脚本数组中获取2个日期(Min和Max)之间的所有日期。我通过JSON从Java获取此数组。
以下是获取最小值和最大值之间日期的方法:
function getDatesBetweenRange(min,max){
var subArray = [];
var value, jCntr=0;
for(var iCntr=0;iCntr<dates.length;iCntr++){
value = dates[iCntr];
if(value>max)
break;
if(value >=min && value <=max){
subArray[jCntr++]= value;
}
}
return subArray;
}
由于数组按升序排序;如果我得到的最大值超过参数中提供的最大值,我就会打破循环。
有没有其他有效的方法从Java Script数组中获取值?
答案 0 :(得分:7)
这是一个似乎more efficient的半二进制过滤方法(至少在我的浏览器中是Chrome,Firefox,IE9)
function filterBinary(arr,min,max){
var len = arr.length
,up = -1
,down = len
,rrange= []
,mid = Math.floor(len/2)
;
while (up++<mid && down-->mid){
if (arr[up]>=max || arr[down]<=min){break;}
if (arr[up]>=min){
rrange.push(arr[up]);
}
if (arr[down]<=max){
rrange.push(arr[down]);
}
}
return rrange;
}
答案 1 :(得分:3)
您可以使用binary search获取indizes,然后使用slice:
Array.prototype.sliceRange = function(min, max) {
if (min > max) return this.sliceRange(max, min);
var l = 0,
r = this.length;
// find an element at index m that is in range
rough: {
while (l < r) {
var m = Math.floor(l + (r - l) / 2);
if (this[m] < min)
l = m + 1;
else if (this[m] > max)
r = m;
else
break rough;
}
// l == r: none was found
return [];
}
var lr = m, // right boundary for left search
rl = m; // left boundary for right search
// get first position of items in range (l == lr)
while (l < lr) {
m = Math.floor(l + (lr - l) / 2);
if (this[m] < min)
l = m + 1;
else
lr = m;
}
// get last position of items in range (r == rl)
while (rl < r) {
m = Math.floor(rl + (r - rl) / 2);
if (this[m] > max)
r = m;
else
rl = m + 1;
}
// return the items in range
return this.slice(l, r);
}
(Demo)
然而,@ Qnan只进行一次半搜索(而不是我的三次搜索)的方法更直接,不应该有任何缺点。我只会使用导致精确索引的循环:
Array.prototype.sliceRange = function(min, max) {
if (min > max) return this.sliceRange(max, min);
var l = 0,
c = this.length,
r = c;
// get first position of items in range (l == c)
while (l < c) {
var m = Math.floor(l + (c - l) / 2);
if (this[m] < min)
l = m + 1;
else
c = m;
}
// get last position of items in range (c == r)
while (c < r) {
var m = Math.floor(c + (r - c) / 2);
if (this[m] > max)
r = m;
else
c = m + 1;
}
// return the items in range
return this.slice(l, r);
}
答案 2 :(得分:1)
这里大致是二进制搜索在这种情况下的样子
var dates = [1333391400000,1335292200000,1335810600000,1336329000000,1336933800000,1337020200000,
1337193000000,1337538600000,1337625000000,1337797800000,1338316200000,1338921000000,
1339093800000,1339439400000,1340303400000,1341772200000,1342463400000,1343068200000];
function getDatesBetweenRange(min, max) {
var subArray = [];
var value, iCntr;
var start, end;
var low = 0, high = dates.length - 1;
while (high - low > 1) {
centre = Math.floor((high + low) / 2);
if (dates[centre] < min)
low = centre;
else
high = centre;
}
start = low;
high = dates.length - 1
while (high - low > 1) {
centre = Math.floor((high + low) / 2);
if (dates[centre] > max)
high = centre;
else
low = centre;
}
end = high;
for (var i = start; i < end; i++) {
value = dates[i];
if (value < min) {
continue;
}
if (value > max) {
break;
}
subArray.push(value);
}
return subArray;
}
console.log(getDatesBetweenRange(1337193000000, 1337797800000));
这是@Stano的代码,除了二次搜索运行两次以识别更严格的边界。当然,它可以得到改善。
答案 3 :(得分:1)
尝试像这样优化循环的问题(在达到最大值后突破排序列表)是每次迭代时都要进行检查。在某些情况下,它可以更快地遍历整个列表。特别是当您搜索的值位于列表的末尾时(例如,最近的日期)
但是,如果它有所作为,则需要二进制搜索算法。 Lodash有一个函数,它使用二进制搜索来检索将插入值的索引。将其与切片相结合,结果应该是最佳的。
使用[Lodash] [1]
// sliced : get all values between+including min-max from sorted array of numbers
// @param array sorted timestamps
// @param min timestamp minimum
// @param max timestamp maximum
function sliced(array,min,max){
return array.slice(_.sortedIndex(array, min),_.sortedIndex(array, max)+1);
}
答案 4 :(得分:0)
function getDatesBetweenRange(min,max)
{
var subArray = dates.slice(0,dates.length-1);
for(var iCntr=0;iCntr<dates.length;iCntr++)
{
if(!(dates[iCntr] >=min && dates[iCntr] <=max))
{
subArray.splice(iCntr,1);
}
}
return subArray;
}