Відповіді:
Версія 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
і це ES5, навіть якщо ви відповідаєте в 2016 році та інші рішення - це просто добре, хоча цей ноб, який задав це питання, явно не був програмістом.
O(n)
рішення виконує приблизно 100 кс / с менше, ніж @paxdiablo O(log n)
на випадкових числах. При розробці алгоритму завжди сортуйте спочатку вони говорять. (За винятком випадків, коли ви знаєте, чим займаєтесь, і у вас є орієнтири, які вам підкорять.)
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) просто з масивами і не піклуючись про нижню межу.
Моя відповідь на подібне запитання - це також облік зв’язків, і він знаходиться в простому Javascript, хоча він не використовує двійковий пошук, тому це 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
. Тепер це ще швидше.
Для невеликого діапазону найпростіша річ - мати масив карт, де, наприклад, 80-й запис мав би в ньому значення 82 для використання вашого прикладу. Для набагато більшого, рідкого діапазону, ймовірно, шлях - це двійковий пошук.
За допомогою мови запиту ви можете запитувати значення на деякій відстані з будь-якої сторони вашого вхідного номера, а потім сортувати отриманий скорочений список. Але SQL не має хорошого поняття "наступний" або "попередній", щоб дати вам "чисте" рішення.
Інший варіант, у нас є круговий діапазон, що з'єднує голову до ніг і приймає лише мінімальне значення для даного входу. Це допомогло мені отримати значення 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
Вихідний код (Java):
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
масиву.