diziden en yakın sayıyı al


163

Eksi 1000'den artı 1000'e bir sayı var ve içinde sayılar içeren bir dizi var. Bunun gibi:

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

Dizinin en yakın sayısında yaptığım sayının değişmesini istiyorum.

Örneğin almasını 80istediğim sayı olarak alıyorum 82.


2
Inanılmayacak basit: değişken kenara x, karşılaştırma tek dizi birine geçmesi ibuna arasındaki fark ise, bir dizi geçerli bir numaraya igüncel değeri daha küçük olduğu x, set xmevcut dizi numarasına. Tamamlandığında x, sayı idiziden en yakın olana sahiptir.
deceze

Yanıtlar:


208

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


1
dezavantajı, sadece azaltmanın geri çağrısı bildirilen değişkenlerle aynı kapsamdan çağrıldığında çalışır. Azaltmak goaliçin geçemediğiniz için, global bir kapsamdan referans almalısınız.
7yl4r

5
bunu yapmak için daha yüksek bir sıra işlevi kullanabilir.
dmp

3
@ 7yl4r veya bir fonksiyonda sarmak? ;)
Dominic

1
@ 7yl4r gerçekten değil ... bunu başarmak için bağlama kullanabilirsiniz ... hedef) <Math.abs (önceki - hedef)? curr: önceki); } // main.js var sayım = [4, 9, 15, 6, 2], hedef = 5; sayım azaltın (redüktör. bağlama (boş, hedef)); ---------- Yorumlara nasıl kod koyacağımı bilmiyorum hahaha.
Mauricio Soares

Bu, liste sipariş edildiğinde en uygun olmayan ancak küçük listeler için uygun olan her öğeyi yineler. İkili arama olmasa bile, sonraki sayı başka bir yolsa bir döngü çıkabilir.
Dominic

144

İş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.


2
@micha, cevaba eqivalent JS kodunu ekledim, sadece alıştığım dilleri değiştirmek için biraz zaman aldı :-)
paxdiablo

2
Büyük veri kümeleriniz varsa bu algoritma için çalışma zamanı yetersiz.
ylun.ca

4
@ ylun.ca, verilerin sıralandığı sorusunda açık bir ifade olmadığından (örnek sıralanır ancak bu bir tesadüf olabilir), O (n) 'den daha iyi verimlilik elde edemezsiniz. Her durumda, bu boyuttaki bir veri kümesi için, verimlilik çoğunlukla önemsizdir. Ama geçerli bir nokta bu yüzden cevabı daha eksiksiz hale getirmek için bu etkiye notlar ekleyeceğim.
paxdiablo

1
Keşke birden fazla kez oy verebilseydim! Yığın taşmasıyla ilgili daha fazla cevap, bu tür çabaların içine girmelidir.
Richard Vanbergen

48

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

24

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


8
Daha ne kadar neşeli.
Hot Licks

6
Sadece JavaScript kullandığından bunun daha iyi bir çözüm olduğunu iddia ediyorum. Kabul edilen cevap, orijinal soruda belirtilmeyen ve bu soruya bakan başkalarının kullanamayacağı jQuery kullanır.
Sean the Bean

17

Sıralanmamış dizilerle çalışır

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:

  1. 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ı)
  2. 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)
  3. 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 .


1
Bilmiyorum ama sanırım bu pratikte olduğu için performans şüpheleri olabilir 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.
noob

1
Evet öğrendiğini görmek harika! Bu arada, sadece daha kötü performans sergilediğini iddia etmeyen performans şüpheleri hakkında konuştum ama sizin için sayıları çalıştırdım ve 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.)
noob

1
Basit bir çözüm için aksesuarlar. Kullanım durumum için harika çalışıyor (noob gibi önceden sıralanmış bir diziye sahip olma
lüksüm

2
Tüm dizilerde yeniden kullanılabilir hale getirmek için findClosest'in geri arama azaltma işlevini geri vermesini sağlayabilirsiniz: const findClosest = goal => (a,b) => Math.abs(a - goal) < Math.abs(b - goal) ? a : b;
Jakob E

1
Örnek: [2, 42, 82, 122, 162, 202, 242, 282, 322, 362].reduce(findClosest(80))
Jakob E

11

Sıralı diziler için (doğrusal arama)

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


Buradaki strateji iyi olsa da, bunun birkaç yazım hatası var. Örnek a[i]veya i[0].
Wesley Workman

1
Teşekkürler, @WesleyWorkman. Onları düzelttik. Umarım hepsine sahibim. Bu arada, başkalarının cevaplarını da düzenleyebilirsiniz.
Hubert Grzeskowiak

En yüksek değeri elde etmek için yukarıda cevaplanan kodda düzeltmeyi nerede yapmalıyım? Örnek: [110, 111, 120, 140, 148, 149, 155, 155, 177, 188, 190] 150'yi ararsam, 149'u 155 almam gerekir. Denedim ama bunu çözmekte zorlanıyorum. Lütfen yardım eder misiniz. Teşekkürler
user1199842

9

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

1
Gerçekten de, konuya çok daha fazlası. ancak "diziden en yakın sayıyı elde etmek" için yine de sıralanmış diziden ilk öğeyi seçmeniz gerekir.
Shaya Ulman

6

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.


Daha küçük değerlerin önceliğine sahip kod:

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

Daha büyük değerlerin önceliğine sahip kod:

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


Yani verilen dizinin sıralandığını varsayalım ... Bu sizi cehennemden çok kurtarır.
Redu

1
op dizisi sıralı görünüyor, bu yüzden evet :)
Nina Scholz

İlk çözüm, aynı sayıyı içeren girdileri iki kez keser. ör.closestValue([ 2, 2, 42, 80 ], 50) === 2
Sébastien Vercammen

@ SébastienVercammen, op'nin verileri benzersiz ve sıralıdır.
Nina Scholz

@NinaScholz OP sadece " İçinde numaraları olan bir dizi var" ve "Ben dizi en yakın sayı değişiklikleri var istiyorum" belirledi . Örnek dizi sadece bir örnektir. Bir Dizi benzersiz girişleri garanti etmez.
Sébastien Vercammen

4

ES6

Sıralanmış ve sıralanmamış dizilerle çalışır

Sayılar Tamsayılar ve Şamandıralar

/**
 * 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

3

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 !


1
Peki alt sınır ne olacak? Her zaman bir sonraki daha yüksek değeri kullanırsınız. Ancak yaklaşımınız bana goog.math.clampsadece dizilerle ve alt sınırla ilgilenmeden (google kapanışı) hatırlatıyor .
noob

Çözümünüz diziden bir sonraki daha yüksek sayıyı döndürür. Ne en yakın ne de kesin değer bulunmaz.
Hubert Grzeskowiak

2

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

https://stackoverflow.com/a/26429528/986160


2

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


Hey, bunun neden olduğunu açıklayabilir misin improved for loop? Ters çevrilmiş döngüler her zaman bir performans iyileştirmesi değildir.
A1rPun

Bu döngü için .lengthbeyan ederken sadece bir kez değerlendirirsiniz i. Ama bence var i = arr.length;while (i--) {}daha da hızlı olurdu
Jon

Cevabımı güncelledim. Ben olarak değiştirdim while. Şimdi daha da hızlı.
Jon

0

Dizide biraz değiştirilmiş bir ikili arama işe yarayacaktır.


3
Gee, bu tuhaf - görünüşe göre birisi ikili aramaları sevmiyor. (Hatta bunun en iyi genel çözüm olduğunu düşündüm.)
Hot Licks

0

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.


0

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

0
#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();
}

0

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.


Sırasız dizi ne olacak?
EdG

Sırasız çıkmayan çözümlerden birini alın, ancak işi birçok kez yapıyorsanız, diziyi bir kez sıralamak daha uygun olabilir. Belirtildiği gibi dizi gerçekten büyükse ikili arama doğrusal olandan daha verimli olacaktır.
Dominic

0

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

-5

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

Mesaj javascript istedi etiketleri
Shannon Hochkins
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.