web-dev-qa-db-fra.com

Quelle est la manière la plus élégante de plafonner un nombre à un segment?

Disons que x, a et b sont des nombres. J'ai besoin de plafonner x aux limites du segment [a, b].

Je peux écrire Math.max(a, Math.min(x, b)), mais je ne pense pas que ce soit très facile à lire. Est-ce que quelqu'un a un moyen intelligent d'écrire cela de manière plus lisible? 

84
Samuel Rossille

La façon dont vous le faites est assez standard. Vous pouvez définir une fonction utilitaire clamp comme décrit ici

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

(Bien que l'extension de la langue intégrée soit généralement mal vue)

154
Otto Allmendinger

une approche moins "mathématique", mais devrait également fonctionner de cette façon, le test </> est exposé (peut-être plus compréhensible que minimiser) mais cela dépend vraiment de ce que vous entendez par "lisible"

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

Mise à jour pour ECMAScript 2017:

Math.clamp(x, lower, upper)

Mais notez qu’à ce jour, c’est une étape 1 proposition . En attendant que cela soit largement supporté, vous pouvez utiliser un polyfill .

31
Tomas Nikodym
Math.clip = function(number, min, max) {
  return Math.max(min, Math.min(number, max));
}
11
CAFxX

Cela ne veut pas être une réponse "juste-utiliser-une-bibliothèque" mais juste au cas où vous utilisez Underscore/Lodash, vous pouvez utiliser .clamp :

_.clamp(yourInput, lowerBound, upperBound);

Pour que: 

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

Voici son implémentation, tirée de Lodash source :

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

Il convient également de noter que Lodash propose des méthodes uniques disponibles en tant que modules autonomes. Par conséquent, si vous n’avez besoin que de cette méthode, vous pouvez simplement l’installer sans le reste de la bibliothèque:

npm i --save lodash.clamp
7
Nobita

Si vous pouvez utiliser les fonctions fléchées es6, vous pouvez également utiliser une approche d'application partielle:

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
4
bingles

Dans l’esprit de la sensualité des flèches, vous pouvez créer un micro Clamp/contraindre/gate/& c. fonction utilisant des paramètres de repos

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

Il suffit ensuite de transmettre trois valeurs

clamp(100,-3,someVar);

C'est-à-dire, encore une fois, si par sexy, vous voulez dire «court»

3
stoke motor

Si vous ne voulez définir aucune fonction, l'écrire comme suit: Math.min(Math.max(x, a), b) n'est pas si mal que ça.

0
Ricardo