รับจำนวนที่ใกล้เคียงที่สุดของอาร์เรย์


163

ฉันมีตัวเลขตั้งแต่ลบ 1,000 ถึงบวก 1,000 และฉันมีอาร์เรย์ที่มีตัวเลขอยู่ในนั้น แบบนี้:

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

ฉันต้องการให้หมายเลขที่ฉันมีการเปลี่ยนแปลงเป็นจำนวนที่ใกล้ที่สุดของอาร์เรย์

ยกตัวอย่างเช่นที่ฉันได้รับเป็นจำนวนฉันต้องการที่จะได้รับ8082


2
ง่ายอย่างเป็นไปไม่ได้: ตั้งค่าตัวแปรxไปผ่านอาร์เรย์หนึ่งต่อหนึ่งเปรียบเทียบiกับหมายเลขปัจจุบันในอาร์เรย์ถ้าความแตกต่างระหว่างมันและiเล็กกว่าค่าปัจจุบันxตั้งxเป็นหมายเลขอาร์เรย์ปัจจุบัน เมื่อเสร็จแล้วxมีจำนวนที่ใกล้เคียงที่สุดiจากอาร์เรย์
หลอกลวง

คำตอบ:


208

เวอร์ชั่น 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);


1
ข้อเสียคือจะใช้งานได้ก็ต่อเมื่อการโทรกลับของลดถูกเรียกจากขอบเขตเดียวกันกับ vars ที่ประกาศไว้ เนื่องจากคุณไม่สามารถผ่านgoalไปลดได้คุณต้องอ้างอิงจากขอบเขตทั่วโลก
7yl4r

5
สามารถใช้ฟังก์ชันลำดับที่สูงขึ้นเพื่อทำเช่นนั้น
dmp

3
@ 7yl4r หรือห่อในฟังก์ชั่นหรือไม่? ;)
Dominic

1
@ 7yl4r ไม่จริง ... คุณสามารถใช้การผูกเพื่อให้บรรลุนี้ ... ---------- // reducer.js ฟังก์ชั่นลด (เป้าหมายก่อนหน้ากระแส) {กลับ (Math.abs (กระแส - เป้าหมาย) <Math.abs (ก่อนหน้า - เป้าหมาย)? กระแส: ก่อนหน้า); } // main.js var counts = [4, 9, 15, 6, 2], เป้าหมาย = 5; นับ. ลด (ลด. ผูก (โมฆะเป้าหมาย)); ---------- ฉันไม่รู้วิธีใส่รหัสในความคิดเห็นฮ่าฮ่าฮ่า
เมาริซิโอ Soares

ซึ่งจะวนซ้ำทุกรายการที่ไม่เหมาะสมหากมีการเรียงลำดับรายการ แต่ใช้ได้กับรายการขนาดเล็ก แม้จะไม่มีการค้นหาแบบไบนารีการวนซ้ำก็สามารถออกได้ถ้าหมายเลขถัดไปเป็นวิธีเพิ่มเติม
Dominic

144

นี่คือโค้ดหลอกที่ควรแปลงเป็นภาษาใด ๆ :

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

ตามที่ระบุไว้ว่าไม่ควรสร้างความแตกต่างอย่างมากสำหรับชุดข้อมูลขนาดเล็กหรือสิ่งที่ไม่จำเป็นต้องรวดเร็วอย่างไม่น่าเชื่อ แต่เป็นตัวเลือกที่คุณอาจต้องการพิจารณา


2
@micha ฉันได้เพิ่มรหัส JS eqivalent ในคำตอบมันใช้เวลาสักครู่ในการเปลี่ยนภาษาจากภาษาที่ฉันคุ้นเคยมากขึ้นในการ :-)
paxdiablo

2
รันไทม์ไม่ดีสำหรับอัลกอริทึมนี้ถ้าคุณมีชุดข้อมูลขนาดใหญ่
ylun.ca

4
@ ylun.ca เนื่องจากไม่มีคำสั่งที่ชัดเจนในคำถามที่ว่าข้อมูลถูกเรียงลำดับ (ตัวอย่างถูกเรียงลำดับ แต่อาจเป็นเรื่องบังเอิญ) คุณจึงไม่สามารถรับประสิทธิภาพที่ดีกว่า O (n) ได้ ไม่ว่าในกรณีใดสำหรับชุดข้อมูลที่ขนาดประสิทธิภาพส่วนใหญ่ไม่เกี่ยวข้อง แต่ประเด็นของคุณคือสิ่งที่ถูกต้องดังนั้นฉันจะเพิ่มบันทึกย่อลงในเอฟเฟกต์นั้นเพื่อหวังว่าจะได้คำตอบที่สมบูรณ์ยิ่งขึ้น
paxdiablo

1
ขอบคุณฉันหวังว่าฉันจะโหวตได้มากกว่าหนึ่งครั้ง! คำตอบเพิ่มเติมเกี่ยวกับการล้นสแต็คควรมีความพยายามเช่นนี้
Richard Vanbergen

48

รุ่น 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]);

24

รหัสการทำงานดังต่อไปนี้:

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
ยิ่ง merrier
Hot Licks

6
ฉันจะเถียงว่านี่เป็นทางออกที่ดีกว่าเพราะใช้เพียง JavaScript คำตอบที่ได้รับการยอมรับนั้นใช้ jQuery ซึ่งไม่ได้กล่าวถึงในคำถามเดิมและคนอื่นที่ดูคำถามนี้อาจไม่ได้ใช้
ฌอนถั่ว

17

ทำงานร่วมกับอาร์เรย์ที่ไม่เรียงลำดับ

ในขณะที่มีการแก้ปัญหาที่ดีบางอย่างที่โพสต์ที่นี่ 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)ดังนั้นการที่จะหาจำนวนที่ใกล้เคียงที่สุดที่เราเพิ่งกลับดัชนีต่ำสุดที่พบในอาร์เรย์ที่กำหนด

ฉันสร้างถังขยะเพื่อแสดงให้เห็นแล้ว


1
ฉันไม่รู้ แต่ฉันคิดว่าอาจมีข้อสงสัยเกี่ยวกับประสิทธิภาพเนื่องจากนี่เป็นเรื่องจริง3nและเป็น ES5 แม้ว่าคุณจะตอบในปี 2559 และโซลูชั่นอื่น ๆ ก็ใช้ได้แม้ว่าผู้ที่ไม่ถามคำถามนี้ชัดเจนว่าไม่ใช่โปรแกรมเมอร์ในเวลานั้น
noob

1
ใช่มันเยี่ยมมากที่เห็นคุณเรียนรู้! โดยวิธีการที่ฉันเพียงพูดถึงข้อสงสัยเกี่ยวกับประสิทธิภาพไม่ได้โต้แย้งว่าจริง ๆ แล้วทำงานได้แย่ลง แต่ฉันวิ่งตัวเลขสำหรับคุณและO(n)โซลูชันของคุณมีประสิทธิภาพประมาณ 100k ops / วินาทีน้อยกว่าแล้ว @paxdiablo O(log n)กับตัวเลขสุ่ม เมื่อออกแบบอัลกอริทึมให้เรียงลำดับก่อนเสมอพวกเขาจะพูด (ยกเว้นถ้าคุณรู้ว่าคุณกำลังทำอะไรอยู่และคุณมีเกณฑ์มาตรฐานในการสำรองข้อมูลคุณ)
noob

1
อุปกรณ์ประกอบฉากสำหรับทางออกที่ง่าย ทำงานที่ดีสำหรับการใช้งานในกรณีของฉัน (ฉันไม่ได้หรูหราของการมีอาร์เรย์ก่อนเรียงเช่น Noob ไม่.)
jaggedsoft

2
คุณสามารถทำให้ findClosest คืนค่าฟังก์ชันลดการเรียกกลับเพื่อให้สามารถนำกลับมาใช้ใหม่ได้ในทุกอาร์เรย์: const findClosest = goal => (a,b) => Math.abs(a - goal) < Math.abs(b - goal) ? a : b;
Jakob E

1
ตัวอย่าง: [2, 42, 82, 122, 162, 202, 242, 282, 322, 362].reduce(findClosest(80))
Jakob E

11

สำหรับอาร์เรย์ที่เรียงลำดับ (การค้นหาเชิงเส้น)

คำตอบทั้งหมดมีสมาธิในการค้นหาผ่านอาร์เรย์ทั้งหมด เมื่อพิจารณาอาร์เรย์ของคุณแล้วและคุณต้องการเพียงจำนวนที่ใกล้ที่สุดนี่อาจเป็นทางออกที่เร็วที่สุด:

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].
Wesley Workman

1
ขอบคุณ @WesleyWorkman เพียงแก้ไขพวกเขา ฉันหวังว่าฉันจะได้รับทั้งหมด อย่างไรก็ตามคุณสามารถแก้ไขคำตอบของผู้อื่นได้
Hubert Grzeskowiak

ที่ฉันต้องทำการแก้ไขในรหัสตอบข้างต้นเพื่อรับค่าใกล้เคียงสูงขึ้น? ตัวอย่าง: [110, 111, 120, 140, 148, 149, 155, 177, 188, 190] ถ้าฉันค้นหา 150 ฉันควรได้ 155 ไม่ใช่ 149 ฉันพยายาม แต่หาทางแก้ไขปัญหาได้ยาก คุณช่วยได้ไหม ขอบคุณ
user1199842

9

โซลูชันทั้งหมดได้รับการออกแบบทางวิศวกรรมมากเกินไป

มันง่ายเหมือน:

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
แน่นอนมากขึ้นไปยังจุดที่ แต่เพื่อ "รับจำนวนที่ใกล้เคียงที่สุดของอาเรย์" คุณยังคงต้องเลือกองค์ประกอบแรกจากอาเรย์ที่เรียงลำดับ
Shaya Ulman

6

วิธีนี้ใช้ ES5 existential quantifier Array#someซึ่งอนุญาตให้หยุดการวนซ้ำหากตรงตามเงื่อนไข

ตรงข้ามกับArray#reduceมันไม่จำเป็นต้องวนซ้ำองค์ประกอบทั้งหมดสำหรับหนึ่งผลลัพธ์

ภายในการเรียกกลับจะมีdeltaการเปรียบเทียบค่าการค้นหาและค่าจริงกับค่าสัมบูรณ์itemและเดลต้าล่าสุด หากมากกว่าหรือเท่ากันการวนซ้ำจะหยุดลงเนื่องจากค่าอื่นทั้งหมดที่มี deltas มากกว่าค่าจริง

ถ้าdeltaในการเรียกกลับมีขนาดเล็กแล้วรายการที่เกิดขึ้นจริงจะได้รับมอบหมายให้ผลและถูกบันทึกไว้ในdeltalastDelta

สุดท้ายค่าขนาดเล็กที่มีสันดอนเท่ากับจะถูกนำเช่นในตัวอย่างด้านล่างซึ่งผลในการ222

หากมีลำดับความสำคัญของค่าที่สูงกว่าการตรวจสอบเดลต้าจะต้องเปลี่ยนจาก:

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


ดังนั้นคุณคิดว่าอาร์เรย์ที่กำหนดถูกจัดเรียง ... นั่นช่วยให้คุณประหยัดเวลาได้มาก
Redu

1
อาร์เรย์ของ op ดูเรียงดังนั้นใช่ :)
Nina Scholz

ทางออกแรกแบ่งอินพุตที่มีจำนวนเท่ากันสองครั้ง เช่นclosestValue([ 2, 2, 42, 80 ], 50) === 2
Sébastien Vercammen

@ SébastienVercammenข้อมูลของ op ไม่เหมือนใครและเรียงลำดับ
Nina Scholz

@NinaScholz OP ระบุว่า"ฉันมีอาร์เรย์ที่มีตัวเลขอยู่ในนั้น"และ "ฉันต้องการว่าจำนวนที่ผมได้มีการเปลี่ยนแปลงจำนวนที่ใกล้ที่สุดของอาร์เรย์" อาร์เรย์ตัวอย่างเป็นเพียงตัวอย่างเดียว อาร์เรย์ไม่รับประกันรายการที่ไม่ซ้ำ
Sébastien Vercammen

4

ES6

ทำงานร่วมกับอาร์เรย์ที่เรียงลำดับและไม่เรียงลำดับ

ตัวเลขจำนวนเต็มและจำนวนลอยยินดีต้อนรับ Strings

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

3

ฉันไม่รู้ว่าควรตอบคำถามเก่าหรือไม่ แต่เมื่อโพสต์นี้ปรากฏขึ้นครั้งแรกในการค้นหาของ 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);

นั่นคือทั้งหมด!


1
แล้วขอบเขตล่างเป็นเท่าไหร่? คุณใช้ค่าที่สูงขึ้นถัดไปเสมอ แต่วิธีการของคุณทำให้ฉันนึกถึงgoog.math.clamp(google ปิด) เพียงแค่มีอาร์เรย์และไม่สนใจขอบเขตล่าง
noob

โซลูชันของคุณส่งคืนหมายเลขที่สูงกว่าถัดไปจากอาร์เรย์ ไม่พบค่าที่ใกล้ที่สุดหรือค่าที่แน่นอน
Hubert Grzeskowiak

2

คำตอบของฉันสำหรับคำถามที่คล้ายกันคือการบัญชีสำหรับความสัมพันธ์ด้วยและเป็น 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);

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


2

ฉันชอบวิธีการจาก 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? ลูปที่กลับด้านนั้นไม่ได้เป็นการปรับปรุงประสิทธิภาพเสมอไป
A1rPun

คุณประเมิน.lengthเพียงครั้งเดียวเมื่อคุณประกาศiในขณะที่สำหรับวงนี้ แต่ฉันคิดว่าvar i = arr.length;while (i--) {}จะเร็วกว่านี้
Jon

ฉันปรับปรุงคำตอบของฉัน whileฉันเปลี่ยนไป ตอนนี้มันเร็วยิ่งขึ้น
Jon

0

การค้นหาไบนารี่ที่แก้ไขเล็กน้อยบนอาเรย์จะใช้งานได้


3
Gee นั่นแปลกประหลาด - เห็นได้ชัดว่ามีคนไม่ชอบการค้นหาแบบไบนารี (แม้คิดว่าเป็นคำตอบทั่วไปที่ดีที่สุด)
Hot Licks

0

สำหรับช่วงขนาดเล็กสิ่งที่ง่ายที่สุดคือมีอาร์เรย์แผนที่ซึ่งเช่นรายการที่ 80 จะมีค่า 82 อยู่ในนั้นเพื่อใช้ตัวอย่างของคุณ สำหรับช่วงห่างขนาดใหญ่มากอาจเป็นวิธีการค้นหาแบบไบนารี

ด้วยภาษาคิวรีคุณสามารถค้นหาค่าระยะทางทั้งสองข้างของหมายเลขอินพุตของคุณจากนั้นเรียงลำดับรายการผลลัพธ์ที่ลดลง แต่ SQL ไม่มีแนวคิดที่ดีของ "ถัดไป" หรือ "ก่อนหน้า" เพื่อให้โซลูชันที่ "สะอาด"


0

อีกตัวแปรหนึ่งที่นี่เรามีช่วงวงกลมเชื่อมต่อหัวจรดเท้าและยอมรับเฉพาะค่าขั้นต่ำเพื่อรับอินพุต สิ่งนี้ช่วยให้ฉันได้รับค่ารหัสถ่านสำหรับหนึ่งในอัลกอริทึมการเข้ารหัส

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

มีประสิทธิภาพมากที่สุดคือการค้นหาแบบไบนารี อย่างไรก็ตามแม้โซลูชั่นที่เรียบง่ายสามารถออกเมื่อหมายเลขถัดไปเป็นคู่ต่อไปจากปัจจุบัน โซลูชันเกือบทั้งหมดที่นี่ไม่ได้คำนึงถึงว่ามีการสั่งซื้ออาร์เรย์และวนซ้ำทุกสิ่ง: /

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

สิ่งนี้สามารถเรียกใช้บน non-primitives ได้เช่นกัน closest(data, 21, item => item.age)

เปลี่ยนfindเป็นfindIndexเพื่อส่งคืนดัชนีในอาร์เรย์


แล้วอาเรย์ที่ไม่มีการเรียงลำดับล่ะ?
EdG

สำหรับการไม่เรียงลำดับใช้หนึ่งในโซลูชันที่ไม่ออกอย่างไรก็ตามถ้าคุณกำลังทำงานหลาย ๆ ครั้งอาจเป็นวิธีที่ดีที่สุดในการจัดเรียงอาร์เรย์หนึ่งครั้ง ดังที่ได้กล่าวมาแล้วถ้าอาร์เรย์มีขนาดใหญ่มากการค้นหาแบบไบนารีจะมีประสิทธิภาพมากกว่าแบบเชิงเส้น
Dominic

0

เพื่อหาสองหมายเลขที่ใกล้เคียงที่สุดในอาร์เรย์

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

นี่คือข้อมูลโค้ดเพื่อค้นหาองค์ประกอบที่ใกล้เคียงที่สุดกับตัวเลขจากอาร์เรย์ใน 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;
    }
}

โพสต์ถามถึงจาวาสคริปต์ในแท็ก
Shannon Hochkins
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.