Wat is de meest elegante manier om een ​​getal aan een segment te koppelen?

Laten we zeggen dat x, aen bgetallen zijn. Ik moet xbeperken tot de grenzen van het segment [a, b].

Met andere woorden, ik heb een klemfunctienodig:

clamp(x) = max( a, min(x, b) )

Kan iemand hier een beter leesbare versie van bedenken?


Antwoord 1, autoriteit 100%

De manier waarop je het doet is vrij standaard. U kunt een hulpprogramma clamp-functie definiëren:

/**
 * Returns a number whose value is limited to the given range.
 *
 * Example: limit the output of this computation to between 0 and 255
 * (x * 255).clamp(0, 255)
 *
 * @param {Number} min The lower boundary of the output range
 * @param {Number} max The upper boundary of the output range
 * @returns A number in the range [min, max]
 * @type Number
 */
Number.prototype.clamp = function(min, max) {
  return Math.min(Math.max(this, min), max);
};

(Hoewel het uitbreiden van ingebouwde taal over het algemeen afgekeurd wordt)


Antwoord 2, autoriteit 36%

een minder “wiskunde”-georiënteerde benadering, maar zou ook moeten werken, op deze manier wordt de </ >-test zichtbaar (misschien begrijpelijker dan minimaxen) maar het hangt er echt van af wat je bedoelt met “leesbaar”

function clamp(num, min, max) {
  return num <= min 
    ? min 
    : num >= max 
      ? max 
      : num
}

Antwoord 3, autoriteit 28%

Er is een voorstel om een ​​toevoeging aan het ingebouwde Math-object toe te voegen om dit te doen:

Math.clamp(x, lower, upper)

Maar houd er rekening mee dat het vanaf vandaag een fase 1 voorstel. Totdat het breed wordt ondersteund (wat niet gegarandeerd is), kunt u een polyfillgebruiken een>.


Antwoord 4, autoriteit 13%

Een eenvoudige manier zou zijn om

Math.max(min, Math.min(number, max));

en je kunt natuurlijk een functie definiëren die dit omhult:

function clamp(number, min, max) {
  return Math.max(min, Math.min(number, max));
}

Oorspronkelijk heeft dit antwoord de bovenstaande functie ook toegevoegd aan het globale Math-object, maar dat is een overblijfsel uit een vervlogen tijdperk, dus het is verwijderd (bedankt @Aurelio voor de suggestie)


Antwoord 5, autoriteit 6%

Dit wil geen “gewoon-gebruik-een-bibliotheek”-antwoord zijn, maar voor het geval je Lodash gebruikt, kun je .clamp:

_.clamp(yourInput, lowerBound, upperBound);

Zodat:

_.clamp(22, -10, 10); // => 10

Hier is de implementatie, overgenomen uit Lodash bron:

/**
 * The base implementation of `_.clamp` which doesn't coerce arguments.
 *
 * @private
 * @param {number} number The number to clamp.
 * @param {number} [lower] The lower bound.
 * @param {number} upper The upper bound.
 * @returns {number} Returns the clamped number.
 */
function baseClamp(number, lower, upper) {
  if (number === number) {
    if (upper !== undefined) {
      number = number <= upper ? number : upper;
    }
    if (lower !== undefined) {
      number = number >= lower ? number : lower;
    }
  }
  return number;
}

Het is ook vermeldenswaard dat Lodash afzonderlijke methoden beschikbaar stelt als zelfstandige modules, dus als u alleen deze methode nodig heeft, kunt u deze installeren zonder de rest van de bibliotheek:

npm i --save lodash.clamp

Antwoord 6, autoriteit 4%

Als u es6-pijlfuncties kunt gebruiken, kunt u ook een gedeeltelijke applicatiebenadering gebruiken:

const clamp = (min, max) => (value) =>
    value < min ? min : value > max ? max : value;
clamp(2, 9)(8); // 8
clamp(2, 9)(1); // 2
clamp(2, 9)(10); // 9
or
const clamp2to9 = clamp(2, 9);
clamp2to9(8); // 8
clamp2to9(1); // 2
clamp2to9(10); // 9

Antwoord 7, autoriteit 3%

Als je geen functie wilt definiëren, is het niet zo erg om het als Math.min(Math.max(x, a), b)te schrijven.


Antwoord 8

Dit breidt de ternaire optie uit tot if/else, wat gelijk is aan de ternaire optie, maar de leesbaarheid niet in gevaar brengt.

const clamp = (value, min, max) => {
  if (value < min) return min;
  if (value > max) return max;
  return value;
}

Verkleint tot 35b (of 43b bij gebruik van function):

const clamp=(c,a,l)=>c<a?a:c>l?l:c;

Ook, afhankelijk van de perf-tooling of browser die u gebruikt, krijgt u verschillende resultaten of de op wiskunde gebaseerde implementatie of ternaire implementatie sneller is. Bij ongeveer dezelfde prestaties zou ik kiezen voor leesbaarheid.


Antwoord 9

In de geest van pijl-sexiness, zou je een micro kunnen maken
klem/beperking/poort/&c. functie met behulp van rustparameters

var clamp = (...v) => v.sort((a,b) => a-b)[1];

Geef dan gewoon drie waarden door

clamp(100,-3,someVar);

Dat wil zeggen, nogmaals, als je met sexy ‘kort’ bedoelt


Antwoord 10

Mijn favoriet:

[min,x,max].sort()[1]

Other episodes