Yanıtlar:
ES5 Sürümü:
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);
goaliçin geçemediğiniz için, global bir kapsamdan referans almalısınız.
İşte herhangi bir yordamsal dile dönüştürülebilir olması gereken sözde kod:
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
Sadece verilen sayı ve her dizi elemanı arasındaki mutlak farkları çözer ve size minimum fark olanlardan birini verir.
Örnek değerler için:
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.
Kavramın bir kanıtı olarak, bunu eylemde göstermek için kullandığım Python kodu:
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)
Ve gerçekten Javascript'e ihtiyacınız varsa , işlevi gösteren tam bir HTML dosyası için aşağıya bakın:
<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>
Örneğin, veri öğeleriniz sıralanırsa (örnek verilerden çıkarılabilir ancak bunu açıkça belirtmezseniz), verimliliğin artırılabileceğini unutmayın. Örneğin, en yakın öğeyi bulmak için bir ikili arama kullanabilirsiniz.
Ayrıca, saniyede birçok kez yapmanız gerekmedikçe, veri kümeleriniz çok fazla olmadıkça verimlilik iyileştirmelerinin genellikle fark edilmeyeceğini unutmayın. daha büyük .
Eğer varsa do bu şekilde denemek için (ve dizi artan düzende sıralanır garanti edemez) istiyorum, bu iyi bir başlangıç noktasıdır:
<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>
Temel olarak her yineleme için çözüm alanını yarıya indirmek için orta değerin basamaklama ve kontrolünü kullanır , klasik bir O(log N)algoritma iken yukarıdaki sıralı arama 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
Belirtildiği gibi, bu kadar küçük veri setleri için bir fark ya da olmayan şeyler için yapmamalı ihtiyaç kör edici hızlı olması, ancak bu dikkate almak isteyebilirsiniz bir seçenek.
ES6 (2015) Sürüm:
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);
Yeniden kullanılabilirlik için, yer tutucuları destekleyen bir köri işlevini kullanabilirsiniz ( http://ramdajs.com/0.19.1/docs/#curry veya https://lodash.com/docs#curry ). Bu, ihtiyacınız olan şeye bağlı olarak çok fazla esneklik sağlar:
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]);
Aşağıdaki gibi çalışma kodu:
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));
Burada yayınlanan bazı iyi çözümler olsa da, JavaScript bize bir sorunu birçok farklı şekilde çözme araçları sağlayan esnek bir dildir. Tabii ki her şey tarzınıza geliyor. Kodunuz daha işlevselse, azaltma varyasyonunu uygun bulacaksınız , yani:
arr.reduce(function (prev, curr) {
return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);
});
Bununla birlikte, bazıları kodlama stillerine bağlı olarak bunu okumayı zor bulabilir. Bu nedenle sorunu çözmenin yeni bir yolunu öneriyorum:
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
Kullanarak minimum değeri bulan diğer yaklaşımların aksine Math.min.apply, bu giriş dizisinin arrsıralanmasını gerektirmez . Endeksleri önemsememiz veya önceden sıralamamız gerekmiyor.
Açıklık için kodu satır satır açıklayacağım:
arr.map(function(k) { return Math.abs(k - x) })Yeni bir dizi oluşturur, esas olarak verilen sayıların mutlak değerlerini (sayı in arr) eksi girdi numarası ( x) ekleyerek saklar . Sonraki en küçük sayıyı arayacağız (giriş numarasına da en yakın olanı)Math.min.apply(Math, indexArr) Bu, daha önce oluşturduğumuz dizideki en küçük sayıyı bulmanın yasal bir yoludur (bundan başka bir şey değildir)arr[indexArr.indexOf(min)]Bu belki de en ilginç kısım. En küçük sayımızı bulduk, ancak ilk sayıyı ( x) ekleyip çıkarmamamız gerektiğinden emin değiliz . Çünkü eskiden Math.abs()farkı bulurduk. Ancak, array.mapdizinleri aynı yerde tutarak giriş dizisinin bir haritasını (mantıksal olarak) oluşturur. Bu nedenle, en yakın sayıyı bulmak için, verilen dizide bulunan minimumun dizinini döndürürüz indexArr.indexOf(min).Bunu gösteren bir çöp kutusu hazırladım .
3nve 2016'da cevaplasanız ve bu soruyu açıkça soran bu çaylak o zamanlar bir programcı olmasa bile diğer çözümler gayet iyi.
O(n)çözümünüz O(log n)rastgele sayılarda @paxdiablo'dan yaklaşık 100k ops / sn daha az performans gösteriyor . Bir algoritma tasarlarken her zaman önce sıralayın derler. (Ne yaptığınızı biliyorsanız ve sizi destekleyecek kriterleriniz varsa.)
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))
Şimdiye kadar olan tüm cevaplar tüm dizi boyunca arama yapmaya odaklanmaktadır. Dizinizin zaten sıralandığını ve gerçekten sadece en yakın sayıyı istiyorsanız, bu muhtemelen en hızlı çözümdür:
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));
Algoritmanın, örneğin bir ikili ağaç kullanılarak büyük ölçüde geliştirilebileceğini unutmayın.
a[i]veya i[0].
Tüm çözümler aşırı tasarlandı.
Bu kadar basit:
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
Bu çözüm , bir koşul karşılandığında yinelemeyi durdurmaya izin veren ES5 varoluşsal nicelik belirteci kullanır Array#some.
Tersine, Array#reducebir sonuç için tüm unsurları yinelemeye gerek yoktur.
Geri arama içinde, deltaaranan değer ile gerçekitem alınır ve son delta ile karşılaştırılır. Daha büyük veya eşitse yineleme durur, çünkü deltaları olan diğer tüm değerler gerçek değerden daha büyüktür.
Eğer deltageri aramasında küçüktür, daha sonra gerçek öğe sonucu atanır ve deltakaydedilir lastDelta.
Son olarak, eşit delta daha küçük değerleri, aşağıdaki örnekte olduğu gibi, alınan 22hangi sonuçlar 2.
Daha büyük değerlerin önceliği varsa, delta denetimi aşağıdakilerden değiştirilmelidir:
if (delta >= lastDelta) {
için:
if (delta > lastDelta) {
// ^^^ without equal sign
Bu 22, sonuç 42(Daha büyük değerlerin önceliği) ile sonuçlanır .
Bu işlev dizideki sıralı değerlere ihtiyaç duyar.
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
Örnekler:
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
Eski bir soruyu cevaplamam gerekip gerekmediğini bilmiyorum, ancak bu yazı ilk olarak Google aramalarında göründüğü için, burada çözümümü ve 2c'yi eklememi beni affetmeyi umuyordum.
Tembel olmak, bu sorunun çözümünün bir DÖNGÜ olduğuna inanamadım, bu yüzden biraz daha araştırdım ve filtre işleviyle geri döndüm :
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);
Bu kadar !
goog.math.clampsadece dizilerle ve alt sınırla ilgilenmeden (google kapanışı) hatırlatıyor .
Benzer bir soruya cevabım da bağları hesaba katıyor ve ikili Javascript'te olmasına rağmen O (N) ve O (logN) değil:
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'ın yaklaşımını seviyorum, ancak içinde küçük bir hata var. Bunun gibi doğru:
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];
}
Aynı zamanda biraz daha hızlı çünkü gelişmiş for döngüyü .
Sonunda fonksiyonumu şöyle yazdım:
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;
};
Test ettim console.time()ve diğer fonksiyondan biraz daha hızlı.
improved for loop? Ters çevrilmiş döngüler her zaman bir performans iyileştirmesi değildir.
.lengthbeyan ederken sadece bir kez değerlendirirsiniz i. Ama bence var i = arr.length;while (i--) {}daha da hızlı olurdu
while. Şimdi daha da hızlı.
Küçük bir aralık için en basit şey, örneğin bir 80. girişin içinde 82 değerine sahip olduğu bir harita dizisine sahip olmaktır. Çok daha geniş, seyrek bir aralık için, muhtemelen gitmenin yolu ikili bir aramadır.
Bir sorgu dili ile, giriş numaranızın her iki tarafındaki mesafeleri sorgulayabilir ve sonuçta elde edilen azaltılmış listeyi sıralayabilirsiniz. Ancak SQL'in size "temiz" bir çözüm sunmak için iyi bir "sonraki" veya "önceki" kavramı yoktur.
Buradaki başka bir varyant, kafa ile ayak parmağını birbirine bağlayan dairesel menzilimiz var ve verilen girişe sadece min değerini kabul ediyor. Bu, şifreleme algoritmasından biri için karakter kodu değerleri almama yardımcı oldu.
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();
}
En verimli ikili arama olacaktır. Bununla birlikte , bir sonraki sayı akımdan daha fazla eşleştiğinde basit çözümler bile çıkabilir . Buradaki neredeyse tüm çözümler, dizinin sipariş edildiğini ve her şeyi yinelediğini dikkate almıyor: /
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);
Bu, ilkel olmayan öğeler üzerinde de çalıştırılabilir; closest(data, 21, item => item.age)
Değişim findiçin findIndexdizideki dizin dönmek için.
Dizideki En Yakın İki Numarayı Bulmak İçin
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));
Karmaşıklık O (nlog (n)) bir dizideki bir sayıya en yakın öğeyi bulmak için Kod snippet'i:
Girdi: - {1,60,0, -10,100,87,56} Eleman: - 56 Dizideki En Yakın Sayı: - 60
Kaynak Kodu (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, karşılaştırma tek dizi birine geçmesiibuna arasındaki fark ise, bir dizi geçerli bir numarayaigüncel değeri daha küçük olduğux, setxmevcut dizi numarasına. Tamamlandığındax, sayıidiziden en yakın olana sahiptir.