답변:
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);
goal
축소를 통과 할 수 없으므로 전역 범위에서이를 참조해야합니다.
다음은 모든 절차 언어로 변환 할 수있는 의사 코드입니다.
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
언급했듯이 작은 데이터 집합이나 맹목적으로 빠를 필요 가없는 것들에는 큰 차이가 없어야 하지만 고려할 수있는 옵션입니다.
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);
재사용 성을 위해 자리 표시자를 지원하는 카레 함수 ( 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]);
아래와 같은 작업 코드 :
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));
여기에 좋은 솔루션이 게시되어 있지만 JavaScript는 여러 가지 방법으로 문제를 해결할 수있는 도구를 제공하는 유연한 언어입니다. 물론 그것은 모두 당신의 스타일에 달려 있습니다. 코드가 더 기능적이라면 축소 변형이 적합하다는 것을 알게 될 것입니다 .
arr.reduce(function (prev, curr) {
return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);
});
그러나 일부는 코딩 스타일에 따라 읽기가 어려울 수 있습니다. 따라서 나는 문제를 해결하는 새로운 방법을 제안한다.
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
반대로 다른 접근 하여 최소 값을 찾는는 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)
.그것을 보여주는 쓰레기통을 만들었 습니다.
3n
2016 년에 실제로 답변하고 ES5 이므로 성능에 의심이있을 수 있습니다. 이 질문을 분명히 한이 멍청한 놈은 당시 프로그래머가 아니었지만 다른 솔루션은 괜찮습니다.
O(n)
솔루션은 O(log n)
임의의 숫자에서 @paxdiablo보다 약 100k ops / sec 적은 성능을 발휘 합니다. 알고리즘을 설계 할 때 항상 먼저 정렬합니다. (내가하는 일을 알고 백업 할 벤치 마크가있는 경우를 제외하고)
const findClosest = goal => (a,b) => Math.abs(a - goal) < Math.abs(b - goal) ? a : b;
[2, 42, 82, 122, 162, 202, 242, 282, 322, 362].reduce(findClosest(80))
지금까지 모든 답변은 전체 배열을 검색하는 데 집중했습니다. 배열이 이미 정렬되어 있고 가장 가까운 숫자 만 원한다는 것을 고려할 때 아마도 가장 빠른 해결책 일 것입니다.
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));
이진 트리를 사용하여 알고리즘을 크게 개선 할 수 있습니다.
a[i]
또는 i[0]
.
모든 솔루션이 과도하게 설계되었습니다.
다음과 같이 간단합니다.
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
이 솔루션은 조건이 충족되는 경우 반복을 중지 할 수있는 ES5 존재 수량 Array#some
자를 사용합니다.
와 반대로 Array#reduce
, 하나의 결과에 대해 모든 요소를 반복 할 필요는 없습니다.
콜백 내에서 delta
검색된 값과 실제 값 사이의 절대 값item
이 취해져 마지막 델타와 비교됩니다. 델타가있는 다른 모든 값이 실제 값보다 크기 때문에 크거나 같으면 반복이 중지됩니다.
경우 delta
콜백에서이 작은 다음, 실제 항목이 결과에 할당하고이 delta
에 저장됩니다 lastDelta
.
마지막으로 아래의 예와 같이 델타가 같은 값이 작을수록 22
결과 는 다음과 같습니다 2
.
더 큰 값의 우선 순위가있는 경우 델타 점검은 다음에서 변경되어야합니다.
if (delta >= lastDelta) {
에:
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
closestValue([ 2, 2, 42, 80 ], 50) === 2
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
예 :
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
이전 질문에 대답해야할지 모르겠지만이 게시물이 Google 검색에 처음 표시되므로 내 솔루션 및 2c를 여기에 추가하는 것을 용서해 주셨으면합니다.
게으 르기 때문에이 질문에 대한 해결책이 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);
그게 다야 !
goog.math.clamp
배열을 사용하고 하한을 신경 쓰지 않고 (Google 폐쇄)를 상기시킵니다 .
비슷한 질문에 대한 나의 대답도 관계를 설명하고 일반 자바 스크립트이지만 바이너리 검색을 사용하지 않으므로 O (N)이며 O (logN)이 아닙니다.
var searchArray= [0, 30, 60, 90];
var element= 33;
function findClosest(array,elem){
var minDelta = null;
var minIndex = null;
for (var i = 0 ; i<array.length; i++){
var delta = Math.abs(array[i]-elem);
if (minDelta == null || delta < minDelta){
minDelta = delta;
minIndex = i;
}
//if it is a tie return an array of both values
else if (delta == minDelta) {
return [array[minIndex],array[i]];
}//if it has already found the closest value
else {
return array[i-1];
}
}
return array[minIndex];
}
var closest = findClosest(searchArray,element);
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()
했고 다른 기능보다 약간 빠르다.
improved for loop
있니? 역 루프가 항상 성능 향상은 아닙니다.
.length
선언 할 때 한 번만 평가 합니다 i
. 하지만 var i = arr.length;while (i--) {}
더 빠를 것 같아요
while
. 이제는 더 빠릅니다.
여기서 또 다른 변형은 머리와 발끝을 연결하는 원형 범위를 가지며 주어진 입력에 최소값 만 허용합니다. 이것은 암호화 알고리즘 중 하나에 대한 char 코드 값을 얻는 데 도움이되었습니다.
function closestNumberInCircularRange(codes, charCode) {
return codes.reduce((p_code, c_code)=>{
if(((Math.abs(p_code-charCode) > Math.abs(c_code-charCode)) || p_code > charCode) && c_code < charCode){
return c_code;
}else if(p_code < charCode){
return p_code;
}else if(p_code > charCode && c_code > charCode){
return Math.max.apply(Math, [p_code, c_code]);
}
return p_code;
});
}
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
class CompareFunctor
{
public:
CompareFunctor(int n) { _n = n; }
bool operator()(int & val1, int & val2)
{
int diff1 = abs(val1 - _n);
int diff2 = abs(val2 - _n);
return (diff1 < diff2);
}
private:
int _n;
};
int Find_Closest_Value(int nums[], int size, int n)
{
CompareFunctor cf(n);
int cn = *min_element(nums, nums + size, cf);
return cn;
}
int main()
{
int nums[] = { 2, 42, 82, 122, 162, 202, 242, 282, 322, 362 };
int size = sizeof(nums) / sizeof(int);
int n = 80;
int cn = Find_Closest_Value(nums, size, n);
cout << "\nClosest value = " << cn << endl;
cin.get();
}
가장 효율적인 이진 검색입니다. 그러나 다음 번호가 현재 번호와 더 일치 하면 간단한 솔루션도 종료 될 수 있습니다 . 여기의 거의 모든 솔루션은 배열이 주문되고 전체를 통해 반복된다는 것을 고려하지 않았습니다.
const closest = (orderedArray, value, valueGetter = item => item) =>
orderedArray.find((item, i) =>
i === orderedArray.length - 1 ||
Math.abs(value - valueGetter(item)) < Math.abs(value - valueGetter(orderedArray[i + 1])));
var data = [2, 42, 82, 122, 162, 202, 242, 282, 322, 362];
console.log('21 -> 2', closest(data, 21) === 2);
console.log('22 -> 42', closest(data, 22) === 42); // equidistant between 2 and 42, select highest
console.log('23 -> 42', closest(data, 23) === 42);
console.log('80 -> 82', closest(data, 80) === 82);
이것은 기본이 아닌 것에서도 실행될 수 있습니다. closest(data, 21, item => item.age)
변경 find
하는 findIndex
배열의 인덱스를 반환합니다.
배열에서 가장 가까운 두 개의 숫자를 찾으려면
function findTwoClosest(givenList, goal) {
var first;
var second;
var finalCollection = [givenList[0], givenList[1]];
givenList.forEach((item, firtIndex) => {
first = item;
for (let i = firtIndex + 1; i < givenList.length; i++) {
second = givenList[i];
if (first + second < goal) {
if (first + second > finalCollection[0] + finalCollection[1]) {
finalCollection = [first, second];
}
}
}
});
return finalCollection;
}
var counts = [2, 42, 82, 122, 162, 202, 242, 282, 322, 362]
var goal = 80;
console.log(findTwoClosest(counts, goal));
Complexity O (nlog (n))의 배열에서 숫자에 가장 가까운 요소를 찾는 코드 스 니펫은 다음과 같습니다.
입력 :-{1,60,0, -10,100,87,56} 요소 :-56 배열에서 가장 가까운 수 :-60
소스 코드 (자바) :
package com.algo.closestnumberinarray;
import java.util.TreeMap;
public class Find_Closest_Number_In_Array {
public static void main(String arsg[]) {
int array[] = { 1, 60, 0, -10, 100, 87, 69 };
int number = 56;
int num = getClosestNumber(array, number);
System.out.println("Number is=" + num);
}
public static int getClosestNumber(int[] array, int number) {
int diff[] = new int[array.length];
TreeMap<Integer, Integer> keyVal = new TreeMap<Integer, Integer>();
for (int i = 0; i < array.length; i++) {
if (array[i] > number) {
diff[i] = array[i] - number;
keyVal.put(diff[i], array[i]);
} else {
diff[i] = number - array[i];
keyVal.put(diff[i], array[i]);
}
}
int closestKey = keyVal.firstKey();
int closestVal = keyVal.get(closestKey);
return closestVal;
}
}
x
배열을 하나씩 살펴보고 배열i
의 현재 숫자와 비교 하십시오. 그 차이i
가의 현재 값보다 작은 경우 현재 배열 번호로x
설정x
하십시오. 완료되면 배열에서x
가장 가까운 번호를 갖 습니다i
.