我有一个从- 1000到+ 1000的数我有一个数组,里面都是数字。是这样的:
[2, 42, 82, 122, 162, 202, 242, 282, 322, 362]
我想让我得到的数字变成数组中最接近的数字。
例如,我的数字是80,我希望它是82。
我有一个从- 1000到+ 1000的数我有一个数组,里面都是数字。是这样的:
[2, 42, 82, 122, 162, 202, 242, 282, 322, 362]
我想让我得到的数字变成数组中最接近的数字。
例如,我的数字是80,我希望它是82。
当前回答
我喜欢Fusion的方法,但其中有一个小错误。这样是正确的:
function closest(array, number) {
var num = 0;
for (var i = array.length - 1; i >= 0; i--) {
if(Math.abs(number - array[i]) < Math.abs(number - array[num])){
num = i;
}
}
return array[num];
}
它也更快一点,因为它使用了改进的for循环。
最后,我这样写函数:
var getClosest = function(number, array) {
var current = array[0];
var difference = Math.abs(number - current);
var index = array.length;
while (index--) {
var newDifference = Math.abs(number - array[index]);
if (newDifference < difference) {
difference = newDifference;
current = array[index];
}
}
return current;
};
我用console.time()测试了它,它比其他函数略快。
其他回答
对于一个较小的范围,最简单的方法是有一个map数组,例如,用你的例子来说,第80个条目的值是82。对于一个更大、更稀疏的范围,可能的方法是二分搜索。
使用查询语言,您可以查询与输入数字任意一侧有一定距离的值,然后对结果减少的列表进行排序。但是SQL并没有一个“下一个”或“上一个”的好概念,来给你一个“干净”的解决方案。
下面是伪代码,可以转换成任何过程语言:
array = [2, 42, 82, 122, 162, 202, 242, 282, 322, 362]
number = 112
print closest (number, array)
def closest (num, arr):
curr = arr[0]
foreach val in arr:
if abs (num - val) < abs (num - curr):
curr = val
return curr
它只是计算出给定数字和每个数组元素之间的绝对差值,然后返回差值最小的一个。
对于示例值:
number = 112 112 112 112 112 112 112 112 112 112
array = 2 42 82 122 162 202 242 282 322 362
diff = 110 70 30 10 50 90 130 170 210 250
|
+-- one with minimal absolute difference.
作为概念的证明,下面是我用来演示这一点的Python代码:
def closest (num, arr):
curr = arr[0]
for index in range (len (arr)):
if abs (num - arr[index]) < abs (num - curr):
curr = arr[index]
return curr
array = [2, 42, 82, 122, 162, 202, 242, 282, 322, 362]
number = 112
print closest (number, array)
而且,如果你真的需要它在Javascript中,请参阅下面的完整HTML文件,其中演示了该函数的操作:
<html>
<head></head>
<body>
<script language="javascript">
function closest (num, arr) {
var curr = arr[0];
var diff = Math.abs (num - curr);
for (var val = 0; val < arr.length; val++) {
var newdiff = Math.abs (num - arr[val]);
if (newdiff < diff) {
diff = newdiff;
curr = arr[val];
}
}
return curr;
}
array = [2, 42, 82, 122, 162, 202, 242, 282, 322, 362];
number = 112;
alert (closest (number, array));
</script>
</body>
</html>
现在请记住,如果数据项已经排序(这可以从示例数据中推断出来,但您没有显式地说明),则可能存在提高效率的空间。例如,您可以使用二分搜索来查找最接近的项。
您还应该记住,除非您需要每秒执行多次,否则效率的提高基本上是不明显的,除非您的数据集变得更大。
如果你确实想尝试这种方式(并且可以保证数组按升序排序),这是一个很好的起点:
<html>
<head></head>
<body>
<script language="javascript">
function closest (num, arr) {
var mid;
var lo = 0;
var hi = arr.length - 1;
while (hi - lo > 1) {
mid = Math.floor ((lo + hi) / 2);
if (arr[mid] < num) {
lo = mid;
} else {
hi = mid;
}
}
if (num - arr[lo] <= arr[hi] - num) {
return arr[lo];
}
return arr[hi];
}
array = [2, 42, 82, 122, 162, 202, 242, 282, 322, 362];
number = 112;
alert (closest (number, array));
</script>
</body>
</html>
它基本上使用括号和中间值的检查来将每次迭代的解空间减少一半,这是一个经典的O(log N)算法,而上面的顺序搜索是O(N):
0 1 2 3 4 5 6 7 8 9 <- indexes
2 42 82 122 162 202 242 282 322 362 <- values
L M H L=0, H=9, M=4, 162 higher, H<-M
L M H L=0, H=4, M=2, 82 lower/equal, L<-M
L M H L=2, H=4, M=3, 122 higher, H<-M
L H L=2, H=3, difference of 1 so exit
^
|
H (122-112=10) is closer than L (112-82=30) so choose H
如前所述,对于小型数据集或不需要盲目快速的东西,这应该没有太大区别,但这是您可能想要考虑的一个选项。
其他答案建议你需要遍历整个数组:
计算每个元素的偏差 跟踪最小偏差及其元素 最后,在遍历整个数组后,返回具有最小偏差的元素。
如果数组已经排序了,那就没有意义了。没有必要计算所有的偏差。例如,在一个100万个元素的有序集合中,你只需要计算~19个偏差(最多)来找到你的匹配。你可以用二进制搜索方法来实现:
function findClosestIndex(arr, element) {
let from = 0, until = arr.length - 1
while (true) {
const cursor = Math.floor((from + until) / 2);
if (cursor === from) {
const diff1 = element - arr[from];
const diff2 = arr[until] - element;
return diff1 <= diff2 ? from : until;
}
const found = arr[cursor];
if (found === element) return cursor;
if (found > element) {
until = cursor;
} else if (found < element) {
from = cursor;
}
}
}
结果:
console.log(findClosestIndex([0, 1, 2, 3.5, 4.5, 5], 4));
// output: 3
console.log(findClosestIndex([0, 1, 2, 3.49, 4.5, 5], 4));
// output: 4
console.log(findClosestIndex([0, 1, 2, 3.49, 4.5, 5], 90));
// output: 5
console.log(findClosestIndex([0, 1, 2, 3.49, 4.5, 5], -1));
// output: 0
这个解决方案使用ES5存在量词数组#some,它允许在满足条件时停止迭代。
与array# reduce相反,它不需要为一个结果迭代所有元素。
在回调中,获取搜索值与实际项之间的绝对增量,并与最后的增量进行比较。如果大于或等于,迭代将停止,因为所有其他具有delta的值都大于实际值。
如果回调中的增量较小,则实际的项被分配给结果,增量保存在lastDelta中。
最后,取具有相等增量的较小值,如下面22的示例,结果为2。
如果有更大的优先级值,delta检查必须从以下更改:
if (delta >= lastDelta) {
to:
if (delta > lastDelta) {
// ^^^ without equal sign
这将得到22,结果为42(较大值的优先级)。
这个函数需要数组中排序的值。
优先级较小的代码:
function closestValue(array, value) { var result, lastDelta; array.some(function (item) { var delta = Math.abs(value - item); if (delta >= lastDelta) { return true; } result = item; lastDelta = delta; }); return result; } var data = [2, 42, 82, 122, 162, 202, 242, 282, 322, 362]; console.log(21, closestValue(data, 21)); // 2 console.log(22, closestValue(data, 22)); // 2 smaller value console.log(23, closestValue(data, 23)); // 42 console.log(80, closestValue(data, 80)); // 82
优先级较高的代码:
function closestValue(array, value) { var result, lastDelta; array.some(function (item) { var delta = Math.abs(value - item); if (delta > lastDelta) { return true; } result = item; lastDelta = delta; }); return result; } var data = [2, 42, 82, 122, 162, 202, 242, 282, 322, 362]; console.log(21, closestValue(data, 21)); // 2 console.log(22, closestValue(data, 22)); // 42 greater value console.log(23, closestValue(data, 23)); // 42 console.log(80, closestValue(data, 80)); // 82
工作代码如下:
var 数组 = [2, 42, 82, 122, 162, 202, 242, 282, 322, 362]; 函数 closest(array, num) { 煮沸i = 0; var minDiff = 1000; 变量; 对于(数组中的 i){ var m = Math.abs(num - array[i]); if (m < minDiff) { 最小差异 = m; ans = 数组[i]; } } 返回和; } 控制台.log(最接近(阵列,88));