Challenge: Get Closest Number in an Array
Andy Zhao (he/him)

Andy Zhao (he/him) @andy

About: uh oh where'd my bio go!

Joined:
Mar 28, 2017

Challenge: Get Closest Number in an Array

Publish Date: Feb 20 '19
18 36

Given an array of numbers nums, and a given number given_num:

nums = [100, 200, 400, 800, 1600, 3200, 6400, 128000]
given_num = 900
Enter fullscreen mode Exit fullscreen mode

Get the number closest to the given_num from the array nums.

In this example, the returned value should be 800.

Go!

A black checkered flag signals go!

Comments 36 total

  • Andy Zhao (he/him)
    Andy Zhao (he/him)Feb 20, 2019

    Ruby:

    nums.min_by { |num| (given_num - num).abs }
    #=> 800
    

    Shamelessly taken from Stack Overflow 🙃 I was in a much more of a "just give me the answer" mood than "let's figure it out" mood.

  • Dian Fay
    Dian FayFeb 20, 2019

    Window functions!

    SELECT unnest
    FROM unnest(ARRAY[100,200,400,800,1600,3200,6400,128000])
    ORDER BY row_number() OVER (ORDER BY abs(900 - unnest))
    LIMIT 1;
    
    • rhymes
      rhymesFeb 20, 2019

      hahaha thinking outside the box :D

      • Dian Fay
        Dian FayFeb 21, 2019

        I looked at it again just now and the row_number is redundant anyway...

        SELECT unnest
        FROM unnest(ARRAY[100,200,400,800,1600,3200,6400,128000])
        ORDER BY abs(900 - unnest)
        LIMIT 1;
        
  • Maegan Wilson
    Maegan WilsonFeb 20, 2019

    I probably over complicated it, but here's a CodePen link with how I did it in JS and outputted it to the HTML side.

  • Harshit
    HarshitFeb 20, 2019

    Java:

            int[] nums = {100, 200, 400, 800, 1600, 3200, 6400, 128000};
            int ans = 0;
            int given_num = 900;
            int minDistance = Integer.MAX_VALUE;
            for (int i =0; i < nums.length; i++) {
                int curDistance = Math.abs(nums[i] - given_num);
                if (curDistance < minDistance) {
                    ans = nums[i];
                    minDistance = curDistance;
                }
            }
            System.out.println(ans);
    

    Trying to optimize no of lines with Java 8 Streams and Lambda.

  • Andrey Vladikin
    Andrey VladikinFeb 20, 2019

    JS:

    const nums = [100, 200, 400, 800, 1600, 3200, 6400, 128000];
    const givenNum = 900;

    nums
    .map(n => ({n, d: Math.abs(n-givenNum)}))
    .sort((n1, n2) => Math.sign(n1.d - n2.d))[0].n

  • kip
    kipFeb 21, 2019

    Rust 🦀

    numbers.iter().min_by_key(|&num| (num - given_num).abs()).unwrap()
    
  • Vicente G. Reyes
    Vicente G. ReyesFeb 21, 2019

    With the help of google, I was able to find the answer to this 😅

    import numpy as np
    def find_nearest(array, value):
    array = np.array(array)
    z=np.abs(array-value)
    y= np.where(z == z.min())
    m=np.array(y)
    x=m[0,0]
    y=m[1,0]
    near_value=array[x,y]

    return near_value
    

    array =np.array([[100, 200, 400, 800, 1600, 3200, 6400, 128000]])
    print(array)
    value = 900
    print(find_nearest(array, value))

    Answer:

    Thanks for this challenge! 🍺

  • Mikhail Korolev
    Mikhail KorolevFeb 21, 2019

    Wolfram Language!

    Nearest[nums, given_num]
    
    Enter fullscreen mode Exit fullscreen mode

    I knew that one day my subscription will come in handy...

  • JavaScript Joel
    JavaScript JoelFeb 21, 2019

    This is a job for Reduce!

    JavaScript:

    const nums = [100, 200, 400, 800, 1600, 3200, 6400, 128000]
    const given_num = 900
    
    const closestReducer = g => (a, b) =>
      Math.abs(g - a) < Math.abs(g - b) ? a : b
    
    nums.reduce(closestReducer(given_num))
    //=> 800
    
  • Pierre Bouillon
    Pierre BouillonFeb 21, 2019

    Here goes Python !

    min(nums, key=lambda x: abs(x - given_num))
    
  • Andrew Bone
    Andrew BoneFeb 21, 2019

    Javascript:

    Let's go for a JS one liner 😉

    nums.sort((a, b) => Math.abs(given_num - a) - Math.abs(given_num - b))[0]
    

    This causes the original array to have its order changed but I don't think that's against the rules 😅

    • bugb
      bugbFeb 21, 2019

      I dont think use sort is good idea:
      Let see:

      [2,3,4,11].sort()
      
      • Andrew Bone
        Andrew BoneFeb 21, 2019

        By including a function to sort by I'm no longer doing an alphabetical sort, which means this problem no longer exists.

          console.log([2,3,4,11].sort((a,b)=>a-b));
        
        Output:
          (4) [2, 3, 4, 11]
        

        The sort() method sorts the elements of an array in place and returns the array. The default sort order is built upon converting the elements into strings, then comparing their sequences of UTF-16 code units values.

        developer.mozilla.org/en-US/docs/W...

        • bugb
          bugbFeb 26, 2019

          yes, by including compareFunction callback, we can solve this problem.

    • Andy Zhao (he/him)
      Andy Zhao (he/him)Feb 21, 2019

      If it outputs the closest number, it works! :)

  • bugb
    bugbFeb 21, 2019

    nums = [100, 200, 400, 800, 1600, 3200, 6400, 128000];
    given_num = 900

    Here is my solution:

    f = a => (m=Math.min(...nums.map(v=>Math.abs(v-given_num))),nums.find(v=>v==given_num - m || v== m-given_num))
    

    Usage:

    f(nums)
    

    Result:

    800
    
    • Gabriel Wu
      Gabriel WuFeb 22, 2019

      Be careful that ... can cause a range error:

      RangeError: Maximum call stack size exceeded

      when the nums array is very large.

  • Dmitry Yakimenko
    Dmitry YakimenkoFeb 21, 2019

    C++, O(n), no sorting, no extra memory allocation beyond storing the input:

    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    int main() {
        vector<int> v{100, 200, 400, 800, 1600, 3200, 6400, 128000};
        int given_num = 900;
    
        cout << *min_element(
            v.begin(), 
            v.end(), 
            [=](int a, int b){ return abs(a - given_num) < abs(b - given_num); }
        );
    
        return 0;
    }
    
  • Modaf
    ModafFeb 21, 2019

    OCaml with list instead of array

    let rec closest num list = match list with
    [] -> failwith "Empty list"
    |[n] -> n
    |h :: q ->
        let closest_q = closest num q in
        let val_h = abs (num - h) in
        let val_q = abs (num - closest_q) in
        if (val_h < val_q) then h else closest_q;;
    
  • James Hickey
    James HickeyFeb 22, 2019

    Here's some C# for everyone:

    var nums = new int[] { 100, 200, 400, 800, 1600, 3200, 6400, 128000 };
    var given_num = 900;
    
    var result = 
        (
            from num in nums
            let diff = Math.Abs(given_num - num)
            orderby diff
            select num
        )
        .First();
    
  • vorsprung
    vorsprungFeb 22, 2019
    package main
    
    
    import (
            "fmt"
            "sort"
    )
    
    func main() {
            l := []int{100, 200, 400, 800, 901, 1600, 3200, 6400, 128000}
            target := 900
            n := sort.SearchInts(l, target)
            if l[n]-target < target-l[n-1] {
                    n += 1
            }
            fmt.Printf("%d\n", l[n-1])
    }
    

    play.golang.org/p/xxzN4y-fPF0

  • Ayoub Fakir
    Ayoub FakirFeb 22, 2019

    Hey! Let's do it the Scala way:

    def closestNumber(x: Int, y: Int, givenNumber: Int): Int = {
        if(abs(givenNumber-x) > abs(givenNumber-y)) {
            y
        } else {
            x
        }
    }
    
    val givenNumber = 900
    val nums = List(100, 200, 400, 800, 1600, 3200, 6400, 128000)
    println(nums.reduce((x, y) => closestNumber(x, y, givenNumber)))
    //==> Prints 800
    

    Thanks for the challenge!

  • Gabriel Wu
    Gabriel WuFeb 22, 2019

    What if there are two numbers that are equally close to the given number?
    I think you should point this out in the description.

  • Gabriel Wu
    Gabriel WuFeb 22, 2019

    Using JavaScript Set:

    const closest_num = (nums, given_num) => {
      const min_dist = Math.min(...nums.map(num => Math.abs(num - given_num)))
      return new Set(nums).has(given_num - min_dist) ? given_num - min_dist : given_num + min_dist
    }
    
    • Gabriel Wu
      Gabriel WuFeb 22, 2019

      Or we can save the intermediate array:

      const closest_num = (nums, given_num) => {
        const absolute_dists = nums.map(num => Math.abs(num - given_num))
        const min_absolute_dist = Math.min(...absolute_dists)
        return nums[absolute_dists.indexOf(min_absolute_dist)]
      }
      
  • Gabriel Wu
    Gabriel WuFeb 22, 2019

    And there is another perspective, instead of iterating numbers, we can iterate distances. Like:

    const closest_num = (nums, given_num) => {
      const set = new Set(nums)
      let i = 0
      while (true) {
        if (set.has(given_num - i)) return given_num - i
        if (set.has(given_num + i)) return given_num + i
        i++
      }
    }
    

    This will normally be slower, but in cases like:

    nums = [10000000, 9999999, 9999998, ..., 1]
    given_num = 10000001

    It will be much faster than other algorithms.

    I have written a benchmark function for this:

    const benchmark = (func) => {
      console.time(func.name)
      func.call(this, Array.from({length: 10000000}, (v, idx) => (10000000 - idx)), 10000001)
      console.timeEnd(func.name)
    }
    

    You can test your function via benchmark(func).

    The solution above yields:

    closest_num: 5037.456787109375ms

    in Chrome.

  • Gabriel Wu
    Gabriel WuFeb 22, 2019

    If the given array is ascending/descending, then the task becomes a binary search.

    The pleasure of programming lies in that even those things appearing to be very simple are also worth thinking.

    • vorsprung
      vorsprungFeb 23, 2019

      yeah, that's why I used a binary search library function in my answer :)

  • Aamir Nazir
    Aamir NazirFeb 25, 2019

    A Python implementation:

    import numpy as np
    def find_nearest(array, value):
        array = np.asarray(array)
        idx = (np.abs(array - value)).argmin()
        return array[idx]
    
    nums = [100, 200, 400, 800, 1600, 3200, 6400, 128000]
    given_num = 900
    
    print(find_nearest(nums, given_num))
    
  • E. Choroba
    E. ChorobaMar 9, 2019

    Perl solution:

    #!/usr/bin/perl
    use warnings;
    use strict;
    use feature qw{ say };
    
    use List::AllUtils qw{ min_by };
    
    my @nums = (100, 200, 400, 800, 1600, 3200, 6400, 128000);
    my $given_num = 900;
    
    say $nums[ min_by { abs($nums[$_] - $given_num) } 0 .. $#nums ];
    
  • Nikolaus
    NikolausOct 16, 2019

    Swift is the most elegant concise and bestest language... ;)

    nums.reduce(nums[0]) { abs($0-given_num) < abs($1-given_num) ? $0 : $1 } 
    

    Of course in actual usage we would make this an extension and check the validity of the array. I came across this post because I needed it so this one's for CGFloat, which is a Swift floating point type (Double, really)

    extension CGFloat {    
        func nearest(arr: [CGFloat]) -> CGFloat {
            guard arr.count > 0 else {
                fatalError("array cannot be empty")
            }
            return arr.reduce(arr[0]) { abs($0-self) < abs($1-self) ? $0 : $1 } 
        }
    }
    
    let nums: [CGFloat] = [100, 200, 400, 800, 1600, 3200, 6400, 128000] 
    let given_num = CGFloat(900)
    
    let nearest = given_num.nearest(nums)
    
    
  • Kenneth Lum
    Kenneth LumFeb 23, 2020

    It looks like the array is sorted. If it is sorted, then the following should be optimal:

    Binary search for the left insertion point, and then for the right insertion point.

    If found, then that's the answer.

    Otherwise, check the left or right number and see which one is closer to the target.

    Time complexity: O(log n)

Add comment