Réponses:
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);
goal
pour réduire, vous devez le référencer à partir d'une portée globale.
Voici le pseudo-code qui devrait être convertible dans n'importe quel langage procédural:
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
Il calcule simplement les différences absolues entre le nombre donné et chaque élément du tableau et vous rend l'un de ceux avec la différence minimale.
Pour les exemples de valeurs:
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.
En guise de preuve de concept, voici le code Python que j'ai utilisé pour montrer cela en action:
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)
Et, si vous en avez vraiment besoin en Javascript, voyez ci-dessous un fichier HTML complet qui montre la fonction en action:
<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>
Maintenant, gardez à l'esprit qu'il peut être possible d'améliorer l'efficacité si, par exemple, vos éléments de données sont triés (cela pourrait être déduit des exemples de données, mais vous ne l'indiquez pas explicitement). Vous pouvez, par exemple, utiliser une recherche binaire pour trouver l'élément le plus proche.
Vous devez également garder à l'esprit que, à moins que vous ne deviez le faire plusieurs fois par seconde, les améliorations d'efficacité seront pour la plupart imperceptibles à moins que vos ensembles de données ne deviennent beaucoup plus volumineux.
Si vous ne voulez essayer cette façon (et peut garantir le tableau est trié dans l' ordre croissant), c'est un bon point de départ:
<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>
Il utilise essentiellement le bracketing et la vérification de la valeur médiane pour réduire de moitié l'espace de solution pour chaque itération, un O(log N)
algorithme classique alors que la recherche séquentielle ci-dessus était 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
Comme indiqué, cela ne devrait pas faire beaucoup de différence pour les petits ensembles de données ou pour les choses qui n'ont pas besoin d'être incroyablement rapides, mais c'est une option que vous voudrez peut-être envisager.
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);
Pour la réutilisation, vous pouvez intégrer une fonction curry qui prend en charge les espaces réservés ( http://ramdajs.com/0.19.1/docs/#curry ou https://lodash.com/docs#curry ). Cela donne beaucoup de flexibilité en fonction de ce dont vous avez besoin:
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]);
Code de travail comme ci-dessous:
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));
Bien qu'il y ait eu quelques bonnes solutions publiées ici, JavaScript est un langage flexible qui nous donne des outils pour résoudre un problème de différentes manières. Tout dépend de votre style, bien sûr. Si votre code est plus fonctionnel, vous trouverez la variante de réduction appropriée, c'est-à-dire:
arr.reduce(function (prev, curr) {
return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);
});
Cependant, certains peuvent trouver cela difficile à lire, en fonction de leur style de codage. C'est pourquoi je propose une nouvelle façon de résoudre le problème:
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
Contrairement à d' autres approches pour trouver la valeur minimale à l'aide de Math.min.apply
, celle-ci ne nécessite pas le arr
tri du tableau d'entrée . Nous n'avons pas besoin de nous soucier des index ou de les trier au préalable.
Je vais vous expliquer le code ligne par ligne pour plus de clarté:
arr.map(function(k) { return Math.abs(k - x) })
Crée un nouveau tableau, stockant essentiellement les valeurs absolues des nombres donnés (nombre dans arr
) moins le nombre d'entrée ( x
). Nous chercherons ensuite le plus petit nombre (qui est également le plus proche du nombre d'entrée)Math.min.apply(Math, indexArr)
C'est un moyen légitime de trouver le plus petit nombre dans le tableau que nous venons de créer auparavant (rien de plus)arr[indexArr.indexOf(min)]
C'est peut-être la partie la plus intéressante. Nous avons trouvé notre plus petit nombre, mais nous ne savons pas si nous devons ajouter ou soustraire le nombre initial ( x
). C'est parce que nous avions l'habitude Math.abs()
de trouver la différence. Cependant, array.map
crée (logiquement) une carte du tableau d'entrée, en gardant les index au même endroit. Par conséquent, pour trouver le nombre le plus proche, nous renvoyons simplement l'index du minimum trouvé dans le tableau donné indexArr.indexOf(min)
.J'ai créé un bac pour le démontrer.
3n
et c'est ES5 même si vous répondez en 2016 et que d'autres solutions sont très bien, même si ce noob qui a posé cette question n'était clairement pas un programmeur à l'époque.
O(n)
solution effectue environ 100000 opérations / s de moins que @paxdiablo O(log n)
sur des nombres aléatoires. Lors de la conception d'un algorithme, trier toujours en premier, disent-ils. (Sauf si vous savez ce que vous faites et que vous avez des repères pour vous soutenir.)
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))
Toutes les réponses jusqu'à présent se concentrent sur la recherche dans l'ensemble du tableau. Étant donné que votre tableau est déjà trié et que vous ne voulez vraiment que le nombre le plus proche, c'est probablement la solution la plus rapide:
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));
Notez que l'algorithme peut être considérablement amélioré, par exemple en utilisant un arbre binaire.
a[i]
ou i[0]
.
Toutes les solutions sont sur-conçues.
C'est aussi simple que:
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
Cette solution utilise le quantificateur existentiel ES5 Array#some
, qui permet d'arrêter l'itération, si une condition est remplie.
À l'opposé de Array#reduce
, il n'est pas nécessaire d'itérer tous les éléments pour un résultat.
À l'intérieur du rappel, un absolu delta
entre la valeur recherchée et le réelitem
est pris et comparé au dernier delta. Si elle est supérieure ou égale, l'itération s'arrête, car toutes les autres valeurs avec leurs deltas sont supérieures à la valeur réelle.
Si le delta
dans le rappel est plus petit, alors l'élément réel est affecté au résultat et le delta
est enregistré dans lastDelta
.
Enfin, des valeurs plus petites avec des deltas égaux sont prises, comme dans l'exemple ci-dessous de 22
, qui aboutit à 2
.
S'il existe une priorité de valeurs supérieures, le contrôle delta doit être modifié de:
if (delta >= lastDelta) {
à:
if (delta > lastDelta) {
// ^^^ without equal sign
Ce serait avec 22
, le résultat42
(priorité des valeurs supérieures).
Cette fonction nécessite des valeurs triées dans le tableau.
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
Exemples:
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
Je ne sais pas si je suis censé répondre à une vieille question, mais comme ce message apparaît en premier sur les recherches Google, j'espérais que vous me pardonneriez d'ajouter ma solution et mon 2c ici.
Étant paresseux, je ne pouvais pas croire que la solution à cette question serait une BOUCLE, alors j'ai cherché un peu plus et suis revenu avec la fonction de filtre :
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);
C'est tout !
goog.math.clamp
(fermeture de google) uniquement avec des tableaux et sans prendre en compte la limite inférieure.
Ma réponse à une question similaire tient également compte des liens et elle est en Javascript simple, bien qu'elle n'utilise pas la recherche binaire, donc c'est O (N) et non 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);
J'aime l'approche de Fusion, mais il y a une petite erreur. Comme ça c'est correct:
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];
}
C'est aussi un peu plus rapide car il utilise la for
boucle améliorée .
À la fin, j'ai écrit ma fonction comme ceci:
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;
};
Je l'ai testé avec console.time()
et il est légèrement plus rapide que l'autre fonction.
improved for loop
? Les boucles inversées ne sont pas toujours une amélioration des performances.
.length
qu'une fois, lorsque vous déclarez i
, alors que pour cette boucle. Mais je pense que ce var i = arr.length;while (i--) {}
serait encore plus rapide
while
. Maintenant c'est encore plus rapide.
Pour une petite plage, le plus simple est d'avoir un tableau de cartes, où, par exemple, la 80e entrée aurait la valeur 82, pour utiliser votre exemple. Pour une plage beaucoup plus large et clairsemée, la recherche binaire est probablement la solution.
Avec un langage de requête, vous pouvez rechercher des valeurs à une certaine distance de chaque côté de votre numéro d'entrée, puis trier la liste réduite résultante. Mais SQL n'a pas un bon concept de "suivant" ou "précédent", pour vous donner une solution "propre".
Une autre variante ici, nous avons une plage circulaire reliant la tête aux pieds et n'accepte que la valeur minimale pour une entrée donnée. Cela m'avait aidé à obtenir des valeurs de code char pour l'un des algorithmes de cryptage.
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();
}
Le plus efficace serait une recherche binaire. Cependant, même des solutions simples peuvent sortir lorsque le numéro suivant est une autre correspondance par rapport au courant . Presque toutes les solutions ici ne prennent pas en compte le fait que le tableau est ordonné et itéré à travers le tout: /
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);
Cela peut également être exécuté sur des non-primitives, par exemple closest(data, 21, item => item.age)
Remplacez find
par findIndex
pour renvoyer l'index dans le tableau.
Pour rechercher deux nombres les plus proches dans le tableau
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));
Voici l'extrait de code pour trouver l'élément le plus proche d'un nombre à partir d'un tableau dans Complexity O (nlog (n)): -
Entrée: - {1,60,0, -10,100,87,56} Élément: - 56 Nombre le plus proche du tableau: - 60
Code source (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
, parcourez le tableau un par un, comparez-lei
au nombre actuel du tableau, si la différence entre celui-ci eti
est inférieure à la valeur actuelle dansx
, définissezx
le numéro du tableau actuel. Une fois terminé,x
a le numéro le plus prochei
du tableau.