找到最接近给定值的索引
Find the closest index to given value
我有一个有序数组:
btnDrag.pos = [0, 65, 131, 196, 259, 323, 388, 453, 517];
还有一个在拖动停止时触发的函数:
btnDrag.draggable({
axis: 'x',
containment: 'parent',
stop: function() {
var index = (function(){
var new_x = btnDrag.position().left;
// now, how to find the closest index in btnDrag.pos relative to new_x ?
// return index;
})();
btnDrag.animate({
'left': (btnDrag.pos[index] + 'px')
});
}
});
数组值是允许 btnDrag 停留的点(在轴 'x' 中)。
因此,该函数必须return最接近 btnDrag go 值的索引。
提前致谢。
是这样的吗?
var closest = btnDrag.pos.reduce(function (prev, curr) {
return (Math.abs(curr - new_x) < Math.abs(prev - new_x) ? curr : prev);
});
给你:
function closest(list, x) {
var min,
chosen = 0;
for (var i in list) {
min = Math.abs(list[chosen] - x);
if (Math.abs(list[i] - x) < min) {
chosen = i;
}
}
return chosen;
}
每次都会计算最小距离,并根据最小值更新所选值。 (http://jsbin.com/dehifefuca/edit?js,console)
由于您的数组已排序,最快的方法是使用 binary search 算法的修改版本:
function closest (arr, x) {
/* lb is the lower bound and ub the upper bound defining a subarray or arr. */
var lb = 0,
ub = arr.length - 1;
/* We loop as long as x is in inside our subarray and the length of our subarray is
greater than 0 (lb < ub). */
while (ub - lb > 1) {
var m = parseInt((ub - lb + 1) / 2); // The middle value
/* Depending on the middle value of our subarray, we update the bound. */
if (arr[lb + m] > x) {
ub = lb + m;
}
else if (arr[lb + m] < x) {
lb = lb + m;
}
else {
ub = lb + m;
lb = lb + m;
}
}
/* After the loop, we know that the closest value is either the one at the lower or
upper bound (may be the same if x is in arr). */
var clst = lb;
if (abs(arr[lb] - x) > abs(arr[ub] - x)) {
clst = ub;
}
return clst; // If you want the value instead of the index, return arr[clst]
}
这是一个fiddle,您可以在其中进行测试:http://jsfiddle.net/Lpzndcbm/4/
与此处提出的所有解决方案不同,此解决方案在 O(log(n))
中运行,而不在 O(n)
中运行。如果你不熟悉complexity,意思是这个算法会在至多O(log(N))
中找到大小为N
的数组中最接近的值循环,而其他人最多会在 N
循环中找到它(使用 N = 10000
,它与 log(10000) ~ 14
(二进制日志)相比有很大的不同)。
请注意,如果您的数组非常小,这可能比原始算法慢。
简单的 for 循环就可以做到:
var btnDrag = {};
btnDrag['pos'] = [0, 65, 131, 196, 259, 323, 388, 453, 517];
new_x = 425;
var index = -1;
for (var i = 0; i < btnDrag.pos.length; i++)
{
if (i < btnDrag.pos.length-1) //loop till i is at 2 positions from the end.
{
//value has to be less then the selected value + 1
if (new_x < btnDrag.pos[i+1])
{
//calculate the half between the values and add it with the first value
// test if new_x is larger then that value.
if ((btnDrag.pos[i+1] - btnDrag.pos[i])/2 + btnDrag.pos[i] > new_x)
{
index = i;
break;
}
else
{
index = i+1;
break;
}
}
}
else
{
//edge cases.
if (new_x < 0)
{
index = 0;
}
else
{
index = btnDrag.pos.length-1;
}
}
}
document.body.innerHTML = btnDrag['pos'][index] + " (" + index + ")";
我有一个有序数组:
btnDrag.pos = [0, 65, 131, 196, 259, 323, 388, 453, 517];
还有一个在拖动停止时触发的函数:
btnDrag.draggable({
axis: 'x',
containment: 'parent',
stop: function() {
var index = (function(){
var new_x = btnDrag.position().left;
// now, how to find the closest index in btnDrag.pos relative to new_x ?
// return index;
})();
btnDrag.animate({
'left': (btnDrag.pos[index] + 'px')
});
}
});
数组值是允许 btnDrag 停留的点(在轴 'x' 中)。
因此,该函数必须return最接近 btnDrag go 值的索引。
提前致谢。
是这样的吗?
var closest = btnDrag.pos.reduce(function (prev, curr) {
return (Math.abs(curr - new_x) < Math.abs(prev - new_x) ? curr : prev);
});
给你:
function closest(list, x) {
var min,
chosen = 0;
for (var i in list) {
min = Math.abs(list[chosen] - x);
if (Math.abs(list[i] - x) < min) {
chosen = i;
}
}
return chosen;
}
每次都会计算最小距离,并根据最小值更新所选值。 (http://jsbin.com/dehifefuca/edit?js,console)
由于您的数组已排序,最快的方法是使用 binary search 算法的修改版本:
function closest (arr, x) {
/* lb is the lower bound and ub the upper bound defining a subarray or arr. */
var lb = 0,
ub = arr.length - 1;
/* We loop as long as x is in inside our subarray and the length of our subarray is
greater than 0 (lb < ub). */
while (ub - lb > 1) {
var m = parseInt((ub - lb + 1) / 2); // The middle value
/* Depending on the middle value of our subarray, we update the bound. */
if (arr[lb + m] > x) {
ub = lb + m;
}
else if (arr[lb + m] < x) {
lb = lb + m;
}
else {
ub = lb + m;
lb = lb + m;
}
}
/* After the loop, we know that the closest value is either the one at the lower or
upper bound (may be the same if x is in arr). */
var clst = lb;
if (abs(arr[lb] - x) > abs(arr[ub] - x)) {
clst = ub;
}
return clst; // If you want the value instead of the index, return arr[clst]
}
这是一个fiddle,您可以在其中进行测试:http://jsfiddle.net/Lpzndcbm/4/
与此处提出的所有解决方案不同,此解决方案在 O(log(n))
中运行,而不在 O(n)
中运行。如果你不熟悉complexity,意思是这个算法会在至多O(log(N))
中找到大小为N
的数组中最接近的值循环,而其他人最多会在 N
循环中找到它(使用 N = 10000
,它与 log(10000) ~ 14
(二进制日志)相比有很大的不同)。
请注意,如果您的数组非常小,这可能比原始算法慢。
简单的 for 循环就可以做到:
var btnDrag = {};
btnDrag['pos'] = [0, 65, 131, 196, 259, 323, 388, 453, 517];
new_x = 425;
var index = -1;
for (var i = 0; i < btnDrag.pos.length; i++)
{
if (i < btnDrag.pos.length-1) //loop till i is at 2 positions from the end.
{
//value has to be less then the selected value + 1
if (new_x < btnDrag.pos[i+1])
{
//calculate the half between the values and add it with the first value
// test if new_x is larger then that value.
if ((btnDrag.pos[i+1] - btnDrag.pos[i])/2 + btnDrag.pos[i] > new_x)
{
index = i;
break;
}
else
{
index = i+1;
break;
}
}
}
else
{
//edge cases.
if (new_x < 0)
{
index = 0;
}
else
{
index = btnDrag.pos.length-1;
}
}
}
document.body.innerHTML = btnDrag['pos'][index] + " (" + index + ")";