noo*_*oob 142 javascript arrays
我有一个从-1000到1000的数字,我有一个数字的数组.像这样:
[2, 42, 82, 122, 162, 202, 242, 282, 322, 362]
Run Code Online (Sandbox Code Playgroud)
我希望我的数字更改为最接近的数组.
例如,我得到80我希望得到的数字82.
小智 174
ES5版本:
var counts = [4, 9, 15, 6, 2],
goal = 5;
var closest = counts.reduce(function(prev, curr) {
return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);
});
console.log(closest);Run Code Online (Sandbox Code Playgroud)
pax*_*blo 140
这是伪代码,应该可以转换成任何过程语言:
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
Run Code Online (Sandbox Code Playgroud)
它只是计算出给定数字和每个数组元素之间的绝对差异,并返回其中一个具有最小差异的那些.
对于示例值:
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.
Run Code Online (Sandbox Code Playgroud)
作为一个概念证明,这里是我用来显示这个代码的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)
Run Code Online (Sandbox Code Playgroud)
而且,如果您真的需要它在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>
Run Code Online (Sandbox Code Playgroud)
现在请记住,例如,如果对数据项进行排序(可以从示例数据中推断出但您没有明确说明它),则可能存在提高效率的余地.例如,您可以使用二进制搜索来查找最近的项目.
你也应该记住,除非你需要做很多次每秒,效率改进将主要容易被忽视的,除非你的数据集得到很多大.
如果你也想尝试一下这种方式(并能保证阵列按升序排序),这是一个很好的起点:
<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>
Run Code Online (Sandbox Code Playgroud)
它主要使用包围和检查中间值来将每个迭代的解空间减少一半,这是一种经典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
Run Code Online (Sandbox Code Playgroud)
如上所述,这对于小型数据集或不需要非常快速的事情来说不应该有太大差别,但它是您可能想要考虑的选项.
小智 40
ES6(2015)版本:
const counts = [4, 9, 15, 6, 2];
const goal = 5;
const output = counts.reduce((prev, curr) => Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);
console.log(output);Run Code Online (Sandbox Code Playgroud)
为了可重用,您可以包含支持占位符的咖喱函数(http://ramdajs.com/0.19.1/docs/#curry或https://lodash.com/docs#curry).根据您的需要,这提供了很大的灵活性:
const getClosest = curry((counts, goal) => {
return counts
.reduce((prev, curr) => Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);
});
const closestTo5 = getClosest(_, 5);
const closestTo = getClosest([4, 9, 15, 6, 2]);
Run Code Online (Sandbox Code Playgroud)
Ume*_*til 23
工作代码如下:
var array = [2, 42, 82, 122, 162, 202, 242, 282, 322, 362];
function closest(array, num) {
var i = 0;
var minDiff = 1000;
var ans;
for (i in array) {
var m = Math.abs(num - array[i]);
if (m < minDiff) {
minDiff = m;
ans = array[i];
}
}
return ans;
}
console.log(closest(array, 88));Run Code Online (Sandbox Code Playgroud)
Dan*_*dru 16
虽然这里发布了一些很好的解决方案,但JavaScript是一种灵活的语言,它为我们提供了以多种不同方式解决问题的工具.当然,这完全取决于你的风格.如果您的代码更具功能性,您会发现适当的reduce变化,即:
arr.reduce(function (prev, curr) {
return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);
});
Run Code Online (Sandbox Code Playgroud)
但是,有些人可能会发现难以阅读,具体取决于他们的编码风格.因此,我提出了解决问题的新方法:
var findClosest = function (x, arr) {
var indexArr = arr.map(function(k) { return Math.abs(k - x) })
var min = Math.min.apply(Math, indexArr)
return arr[indexArr.indexOf(min)]
}
findClosest(80, [2, 42, 82, 122, 162, 202, 242, 282, 322, 362]) // Outputs 82
Run Code Online (Sandbox Code Playgroud)
与使用最小值的其他方法相反Math.min.apply,这个方法不需要对输入数组arr进行排序.我们不需要关心索引或事先对其进行排序.
为清晰起见,我将逐行解释代码:
arr.map(function(k) { return Math.abs(k - x) })创建一个新数组,主要存储给定数字(数字arr输入)的绝对值减去输入数字(x).我们将寻找下一个最小的数字(也是最接近输入数字)Math.min.apply(Math, indexArr) 这是找到我们之前创建的数组中最小数字的合法方式(仅此而已)arr[indexArr.indexOf(min)]这可能是最有趣的部分.我们找到了最小的数字,但我们不确定是否应该加上或减去初始数字(x).那是因为我们过去常常Math.abs()找到差异.但是,array.map创建(逻辑上)输入数组的映射,使索引保持在同一位置.因此,为了找出最接近的数字,我们只返回给定数组中找到的最小值的索引indexArr.indexOf(min).我已经创建了一个展示它的垃圾箱.
Hub*_*iak 10
到目前为止,所有答案都集中在搜索整个阵列.考虑到你的数组已经排序,你真的只想要最接近的数字,这可能是最快的解决方案:
var a = [2, 42, 82, 122, 162, 202, 242, 282, 322, 362];
var target = 90000;
/**
* Returns the closest number from a sorted array.
**/
function closest(arr, target) {
if (!(arr) || arr.length == 0)
return null;
if (arr.length == 1)
return arr[0];
for (var i = 1; i < arr.length; i++) {
// As soon as a number bigger than target is found, return the previous or current
// number depending on which has smaller difference to the target.
if (arr[i] > target) {
var p = arr[i - 1];
var c = arr[i]
return Math.abs(p - target) < Math.abs(c - target) ? p : c;
}
}
// No number in array is bigger so return the last.
return arr[arr.length - 1];
}
// Trying it out
console.log(closest(a, target));Run Code Online (Sandbox Code Playgroud)
注意,例如使用二叉树可以极大地改进算法.
所有解决方案都经过精心设计。
它很简单:
const needle = 5;
const haystack = [1, 2, 3, 4, 5, 6, 7, 8, 9];
haystack.sort((a, b) => {
return Math.abs(a - needle) - Math.abs(b - needle);
});
// 5
Run Code Online (Sandbox Code Playgroud)
ES6
/**
* Finds the nearest value in an array of numbers.
* Example: nearestValue(array, 42)
*
* @param {Array<number>} arr
* @param {number} val the ideal value for which the nearest or equal should be found
*/
const nearestValue = (arr, val) => arr.reduce((p, n) => (Math.abs(p) > Math.abs(n - val) ? n - val : p), Infinity) + val
Run Code Online (Sandbox Code Playgroud)
例子:
let values = [1,2,3,4,5]
console.log(nearestValue(values, 10)) // --> 5
console.log(nearestValue(values, 0)) // --> 1
console.log(nearestValue(values, 2.5)) // --> 2
values = [100,5,90,56]
console.log(nearestValue(values, 42)) // --> 56
values = ['100','5','90','56']
console.log(nearestValue(values, 42)) // --> 56
Run Code Online (Sandbox Code Playgroud)
其他答案表明您需要迭代整个数组:
如果数组已经排序,那就没有意义了。无需计算所有偏差。例如,在 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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
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
Run Code Online (Sandbox Code Playgroud)
此解决方案使用ES5 存在量词 Array#some,如果满足条件,它可以停止迭代。
与相对Array#reduce,它不需要为一个结果迭代所有元素。
在回调内部,将delta获取搜索值和实际值之间的绝对值item,并将其与最后一个增量进行比较。如果大于或等于,则迭代会停止,因为所有其他值及其增量都大于实际值。
如果delta回调中的较小,则将实际项目分配给结果,并将delta保存在中lastDelta。
最后,采用具有相等增量的较小值,如以下示例中的22,结果为2。
如果优先级较高,则必须将增量检查从以下位置更改:
if (delta >= lastDelta) {
Run Code Online (Sandbox Code Playgroud)
至:
if (delta > lastDelta) {
// ^^^ without equal sign
Run Code Online (Sandbox Code Playgroud)
22结果将得到,42(优先级更高的值)。
此函数需要数组中的排序值。
if (delta >= lastDelta) {
Run Code Online (Sandbox Code Playgroud)
if (delta > lastDelta) {
// ^^^ without equal sign
Run Code Online (Sandbox Code Playgroud)
Hot*_*cks -3
对于小范围,最简单的事情是拥有一个映射数组,例如,第 80 个条目的值为 82,以使用您的示例。对于更大、稀疏的范围,可能的方法是二分搜索。
使用查询语言,您可以查询输入数字两侧一定距离的值,然后对生成的简化列表进行排序。但是 SQL 没有“下一个”或“上一个”的良好概念,无法为您提供“干净”的解决方案。
| 归档时间: |
|
| 查看次数: |
99329 次 |
| 最近记录: |