Javascript 从数组中获取最接近的数字

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8584902/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 06:35:40  来源:igfitidea点击:

get closest number out of array

javascriptarrays

提问by noob

I have a number from minus 1000 to plus 1000 and I have an array with numbers in it. Like this:

我有一个从负 1000 到正 1000 的数字,我有一个包含数字的数组。像这样:

[2, 42, 82, 122, 162, 202, 242, 282, 322, 362]

I want that the number I've got changes to the nearest number of the array.

我希望我得到的数字更改为最接近的数组数字。

For example I get 80as number I want it to get 82.

例如,我得到的80数字是我希望它得到的82

回答by Joe Grund

ES5 Version:

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);

回答by paxdiablo

Here's the pseudo-code which should be convertible into any procedural language:

这是应该可以转换为任何程序语言的伪代码:

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

It simply works out the absolute differences between the given number and each array element and gives you back one of the ones with the minimal difference.

它只是计算给定数字和每个数组元素之间的绝对差异,并返回差异最小的一个。

For the example values:

对于示例值:

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.

As a proof of concept, here's the Python code I used to show this in action:

作为概念证明,以下是我用来演示此操作的 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)


And, if you reallyneed it in Javascript, see below for a complete HTML file which demonstrates the function in action:

而且,如果您真的需要在 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>


Now keep in mind there may be scope for improved efficiency if, for example, your data items are sorted (that could be inferred from the sample data but you don't explicitly state it). You could, for example, use a binary search to find the closest item.

现在请记住,例如,如果您的数据项已排序(这可以从示例数据中推断出来,但您没有明确说明),则可能有提高效率的空间。例如,您可以使用二分搜索来查找最接近的项目。

You should also keep in mind that, unless you need to do it manytimes per second, the efficiency improvements will be mostly unnoticable unless your data sets get muchlarger.

你也应该记住,除非你需要做很多次每秒,效率改进将主要容易被忽视的,除非你的数据集得到很多大。

If you dowant to try it that way (and can guarantee the array is sorted in ascending order), this is a good starting point:

如果您确实想以这种方式尝试(并且可以保证数组按升序排序),这是一个很好的起点:

<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>

It basically uses bracketingand checking of the middle value to reduce the solution space by half for each iteration, a classic O(log N)algorithm whereas the sequential search above was O(N):

它基本上使用括号和中间值检查来将每次迭代的解空间减少一半,这是一种经典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

As stated, that shouldn't make much of a difference for small datasets or for things that don't needto be blindingly fast, but it's an option you may want to consider.

如上所述,对于小型数据集或不需要非常快的事物,这应该没有太大区别,但这是您可能想要考虑的一个选项。

回答by Joe Grund

ES6(2015) Version:

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);

For reusability you can wrap in a curry function that supports placeholders (http://ramdajs.com/0.19.1/docs/#curryor https://lodash.com/docs#curry). This gives lots of flexibility depending on what you need:

为了可重用性,您可以使用支持占位符的 curry 函数(http://ramdajs.com/0.19.1/docs/#curryhttps://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]);

回答by Umesh Patil

Working code as below:

工作代码如下:

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));

回答by Dan Mindru

Works with unsorted arrays

适用于未排序的数组

While there were some good solutions posted here, JavaScript is a flexible language that gives us tools to solve a problem in many different ways. It all comes down to your style, of course. If your code is more functional, you'll find the reduce variationsuitable, i.e.:

虽然这里发布了一些很好的解决方案,但 JavaScript 是一种灵活的语言,它为我们提供了以多种不同方式解决问题的工具。当然,这一切都取决于你的风格。如果您的代码功能更强大,您会发现reduce 变体是合适的,即:

  arr.reduce(function (prev, curr) {
    return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);
  });

However, some might find that hard to read, depending on their coding style. Therefore I propose a new way of solving the problem:

但是,根据他们的编码风格,有些人可能会觉得难以阅读。因此,我提出了一种解决问题的新方法:

  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

Contrary to other approachesfinding the minimum value using Math.min.apply, this one doesn't require the input array arrto be sorted. We don't need to care about the indexes or sort it beforehand.

与使用 找到最小值的其他方法相反Math.min.apply这种方法不需要对输入数组arr进行排序。我们不需要关心索引或事先对其进行排序。

I'll explain the code line by line for clarity:

为了清楚起见,我将逐行解释代码:

  1. arr.map(function(k) { return Math.abs(k - x) })Creates a new array, essentially storing the absolute values of the given numbers (number in arr) minus the input number (x). We'll look for the smallest number next (which is also the closest to the input number)
  2. Math.min.apply(Math, indexArr)This is a legit way of finding the smallest number in the array we've just created before (nothing more to it)
  3. arr[indexArr.indexOf(min)]This is perhaps the most interesting part. We have found our smallest number, but we're not sure if we should add or subtract the initial number (x). That's because we used Math.abs()to find the difference. However, array.mapcreates (logically) a map of the input array, keeping the indexes in the same place. Therefore, to find out the closest number we just return the index of the found minimum in the given array indexArr.indexOf(min).
  1. arr.map(function(k) { return Math.abs(k - x) })创建一个新数组,本质上存储给定数字(arr输入数字)减去输入数字 ( x)的绝对值。接下来我们将寻找最小的数字(这也是最接近输入数字的)
  2. Math.min.apply(Math, indexArr)这是在我们之前创建的数组中找到最小数字的合法方法(仅此而已)
  3. arr[indexArr.indexOf(min)]这可能是最有趣的部分。我们找到了最小的数,但不确定是否应该加上或减去初始数 ( x)。那是因为我们过去常常Math.abs()发现差异。但是,array.map创建(逻辑上)输入数组的映射,将索引保持在同一位置。因此,要找出最接近的数字,我们只需返回给定数组中找到的最小值的索引indexArr.indexOf(min)

I've created a bindemonstrating it.

我创建了一个展示它的垃圾箱

回答by Hubert Grzeskowiak

For sorted arrays (linear search)

对于排序数组(线性搜索)

All answers so far concentrate on searching through the whole array. Considering your array is sorted already and you really only want the nearest number this is probably the fastest solution:

到目前为止,所有答案都集中在搜索整个数组。考虑到你的数组已经排序,你真的只想要最近的数字,这可能是最快的解决方案:

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));

Note that the algorithm can be vastly improved e.g. using a binary tree.

请注意,该算法可以大大改进,例如使用二叉树。

回答by Gajus

All of the solutions are over-engineered.

所有的解决方案都是过度设计的。

It is as simple as:

它很简单:

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

回答by Nina Scholz

This solution uses ES5 existential quantifierArray#some, which allows to stop the iteration, if a condition is met.

此解决方案使用 ES5存在量词Array#some,它允许在满足条件时停止迭代。

Opposit of Array#reduce, it does not need to iterate all elements for one result.

与 相反Array#reduce,它不需要为一个结果迭代所有元素。

Inside the callback, an absolute deltabetween the searched value and actual itemis taken and compared with the last delta. If greater or equal, the iteration stops, because all other values with their deltas are greater than the actual value.

在回调内部,delta获取搜索值和实际值之间的绝对值item并与最后一个增量进行比较。如果大于或等于,则迭代停止,因为所有其他值及其增量都大于实际值。

If the deltain the callback is smaller, then the actual item is assigned to the result and the deltais saved in lastDelta.

如果delta回调中的 较小,则将实际项目分配给结果并delta保存在lastDelta.

Finally, smaller values with equal deltas are taken, like in the below example of 22, which results in 2.

最后,取具有相等增量的较小值,如下面的 示例所示22,结果为2

If there is a priority of greater values, the delta check has to be changed from:

如果存在更大值的优先级,则必须将增量检查更改为:

if (delta >= lastDelta) {

to:

到:

if (delta > lastDelta) {
//       ^^^ without equal sign

This would get with 22, the result 42(Priority of greater values).

这将得到22,结果42(更大值的优先级)。

This function needs sorted values in the array.

此函数需要数组中的排序值。



Code with priority of smaller values:

具有较小值优先级的代码:

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

Code with priority of greater values:

具有较大值优先级的代码:

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

回答by FrenchieFred

I don't know if I'm supposed to answer an old question, but as this post appears first on Google searches, I hoped that you would forgive me adding my solution & my 2c here.

我不知道我是否应该回答一个老问题,但由于这篇文章首先出现在 Google 搜索中,我希望你能原谅我在这里添加我的解决方案和我的 2c。

Being lazy, I couldn't believe that the solution for this question would be a LOOP, so I searched a bit more and came back with filter function:

由于懒惰,我无法相信这个问题的解决方案会是一个 LOOP,所以我搜索了更多并返回了过滤功能

var myArray = [2, 42, 82, 122, 162, 202, 242, 282, 322, 362];
var myValue = 80;

function BiggerThan(inArray) {
  return inArray > myValue;
}

var arrBiggerElements = myArray.filter(BiggerThan);
var nextElement = Math.min.apply(null, arrBiggerElements);
alert(nextElement);

That's all !

就这样 !

回答by Sébastien

ES6

ES6

Works with sorted and unsorted arrays

适用于已排序和未排序的数组

Numbers Integers and Floats, Strings welcomed

数字 整数和浮点数,欢迎使用字符串

/**
 * 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

Examples:

例子:

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