简体   繁体   中英

In the case of a tie, how do I return the smaller number in javascript?

I need to write a function that takes two inputs, 'target' (integer) and 'values' (a list of integers), and find which number in 'values' is closest to 'target'. I came up with the following:

var targetNum = 0;
var valuesArr = [2, 4, 6, 8, 10];

function closestToTarget(target, values) {
    var currVal = values[0];
    var diff = Math.abs(target - currVal);
    for (var i = 0; i < values.length; i++) {
        var currDiff = Math.abs(target - values[i]);
        if (currDiff < diff) {
            diff = currDiff;
            currVal = values[i];
        }
    }
    return currVal;
}
alert(closestToTarget(targetNum, valuesArr));

The function works, but I'm unable to return the smaller value in the case of a tie. The best that I could think of was the following which did not work:

function closestToTarget(target, values) {
    var currVal = values[0];
    var diff = Math.abs(target - currVal);
    for (var i = 0; i < values.length; i++) {
        var currDiff = Math.abs(target - values[i]);
        if (currDiff < diff) {
            diff = currDiff;
            currVal = values[i];
        }
        else if (currDiff == diff) {
            return Math.min[currVal, values[i]];
        }
        else {
            return currVal[i - 1];
        }
    }
    return currVal;
}

In the case of a tie, how do I return the smaller number in JavaScript?

Your code looks like it would work try changing Math.min[currVal, values[i]] to Math.min(currVal, values[i]) that should work if your values are ordered (simple syntax issue).

As kojow7 mentioned, the first function should also work as long as the values are ordered.

Otherwise instead of return Math.min(...) you should try to do currVal = Math.min(...) and keep iterating and then returning the currVal after the loop. This just makes sure that you check every value in the values array to make sure that you haven't missed anything (but if it's ordered, then there's no need to keep checking because the difference will only incraese).

Apart from the syntax error (missing parentheses) you could use some ES6 syntax to write a more concise function:

 function closestToTarget(target, values) { const m = Math.min(...values.map( v => Math.abs(target - v))); return Math.min(...values.filter( v => Math.abs(target - v) === m )); } var valuesArr = [2, 4, 6, 8, 10]; // Try several numbers for (var i = 1; i < 12; i++) { console.log(i, closestToTarget(i, valuesArr)); } 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

The trick is that when you find a new best difference, as well as recording the difference ( bestDiff ), you also record the value that caused that difference ( bestVal ).

So now, if you encounter a tie ( currDiff == bestDiff ), you need to check if it's a better tie, that is, check if the current value is smaller than the recorded one ( currVal < bestVal ). If it is, then we update the best values (update both bestDiff and bestVal ).

function closestToTarget(target, values) {
    var currVal = values[0];
    var bestDiff = Math.abs(target - currVal);
    var bestVal = currVal;

    for (var i = 1; i < values.length; i++) {
        var currVal = values[i];
        var currDiff = Math.abs(target - values[i]);
        if (currDiff < bestDiff || (currDiff == bestDiff && currVal < bestVal)) {
            bestDiff = currDiff;
            bestVal = currVal;
        }
    }
    return bestVal;
}

Examples:

closestToTarget(2,[2,4,6,8,10]) // 2
closestToTarget(2,[10,8,6,4,2]) // 2
closestToTarget(3,[10,8,6,4,2]) // 2

Your idea should work, but you could also use your first function but with the addition of something that checks for a lower tie at the end:

function closestToTarget(target, values) {
    var currVal = values[0];
    var diff = Math.abs(target - currVal);
    for (var i = 0; i < values.length; i++) {
        var currDiff = Math.abs(target - values[i]);
        if (currDiff < diff) {
            diff = currDiff;
            currVal = values[i];
        }
    }

    // We found the closest but now check if there's a smaller tie
    if (currVal > target && values.indexOf(target - diff) > -1 ) {
        return target - diff;
    }
    else {
    // if not just return what we originally found
        return currVal;
    }
}

https://jsfiddle.net/vsj0q5u9/2/

function findClosest(inpt, ar) {
   var minDiff = Math.abs(ar[0] - inpt);
   var res = ar[0];
   for (var i = 1; i < ar.length; i++) {
       if(Math.abs((ar[i] - inpt)) < minDiff)
           res = ar[i];
   }
   return res;
}

This is simple example on how to get the closest value in the array for the given input. There will be no lower number to return in case of a tie. if you have more than one closest integer in the array the difference between your input is the same for all the cases of a tie. so don't worry about it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM