Pregunta ¿Cuál es la forma más elegante de limitar un número a un segmento?


Digamos x, a y b son números Necesito tapar x a los límites del segmento [a, b].

puedo escribir Math.max(a, Math.min(x, b)), pero no creo que sea muy fácil de leer. ¿Alguien tiene una manera inteligente de escribir esto de una manera más legible?


75
2017-07-10 08:58


origen


Respuestas:


La forma en que lo haces es bastante estándar. Puedes definir una utilidad clamp funciona como se describe aquí:

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

(Aunque extender extensiones integradas de lenguaje generalmente no está bien visto)


141
2017-07-10 09:02



un enfoque menos "matemático", pero también debería funcionar, de esta manera, la prueba </> está expuesta (tal vez más comprensible que la minimaxing) pero realmente depende de lo que quiere decir con "legible"

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

39
2017-07-10 09:10



Actualización para ECMAScript 2017:

Math.clamp(x, lower, upper)

Pero tenga en cuenta que a partir de hoy, es una Etapa 1 propuesta. Hasta que sea ampliamente compatible, puede usar un polyfill.


19
2017-09-13 19:50



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

10
2017-07-10 09:03



En el espíritu de la sensualidad de las flechas, podrías crear un micro abrazadera / restringir / puerta / & c. función usando parámetros de descanso

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

Entonces solo pasa tres valores

clamp(100,-3,someVar);

Es decir, de nuevo, si por sexy, te refieres a 'corto'


3
2018-04-26 18:15



Esto no quiere ser una respuesta de "solo use una biblioteca", pero en caso de que esté usando Underscore / Lodash puede usar .clamp:

_.clamp(yourInput, lowerBound, upperBound);

Así que eso:

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

Aquí está su implementación, tomada de Lodash fuente:

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

Además, vale la pena señalar que Lodash pone a disposición los métodos individuales como módulos independientes, por lo que, en caso de que solo necesite este método, puede simplemente instalarlo sin el resto de la biblioteca:

npm i --save lodash.clamp

3
2017-11-03 17:36



Si puede usar funciones de flecha es6, también puede usar un enfoque de aplicación parcial:

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

2
2017-11-02 20:46



También puedes usar esto reutilizable componente de abrazadera numérica que devuelve un número cuyo valor está limitado al rango dado.

Ejemplo:

clamp(50, 5, 10) // => 5

Cómo funciona:

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

1
2018-06-05 08:26



Si no quiere definir ninguna función, escríbala como Math.min(Math.max(x, a), b) no es tan malo


0
2018-02-15 17:44



Mi favorito:

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

-1
2018-03-04 19:15