[javascript] 배열에서 가장 가까운 숫자를 얻습니다

마이너스 1000에서 플러스 1000까지의 숫자가 있고 숫자가있는 배열이 있습니다. 이처럼 :

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

내가 가진 숫자가 가장 가까운 배열 수로 변경되기를 원합니다.

예를 들어 나는 80숫자로 얻고 싶습니다 82.



답변

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


답변

다음은 모든 절차 언어로 변환 할 수있는 의사 코드입니다.

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소트 . 인덱스를 신경 쓰거나 미리 정렬 할 필요는 없습니다.

명확성을 위해 코드를 한 줄씩 설명하겠습니다.

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

그것을 보여주는 쓰레기통을 만들었 습니다.


답변

정렬 된 배열 (선형 검색)

지금까지 모든 답변은 전체 배열을 검색하는 데 집중했습니다. 배열이 이미 정렬되어 있고 가장 가까운 숫자 만 원한다는 것을 고려할 때 아마도 가장 빠른 해결책 일 것입니다.

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

이진 트리를 사용하여 알고리즘을 크게 개선 할 수 있습니다.


답변

모든 솔루션이 과도하게 설계되었습니다.

다음과 같이 간단합니다.

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