Какой самый элегантный способ укусить число в сегменте?

Скажем, x, a и b - числа. Мне нужно ограничить x до границ сегмента [a, b].

Я могу написать Math.max(a, Math.min(x, b)), но я не думаю, что это очень легко читать. У кого-нибудь есть умный способ написать это более читаемым способом?

Ответ 1

То, как вы это делаете, довольно стандартно. Вы можете определить функцию утилиты clamp, как описано здесь:

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

(Хотя расширение языковых встроенных функций обычно не одобряется)

Ответ 2

менее ориентированный на "математику" подход, но также должен работать таким образом, / " > (возможно, более понятным, чем минимакс), но это действительно зависит от того, что вы подразумеваете под" читаемым"

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

Ответ 3

Обновление для ECMAScript 2017:

Math.clamp(x, lower, upper)

Но обратите внимание, что на сегодняшний день это этап 1 proposal. Пока он не будет широко поддержан, вы можете использовать polyfill.

Ответ 4

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

Ответ 5

В духе сексуальности стрелки вы можете создать микро зажим/ограничить/ворота/& C. функция с использованием параметров отдыха

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

Затем просто передайте три значения

clamp(100,-3,someVar);

То есть, опять же, если по сексуальности вы имеете в виду "короткие"

Ответ 6

Это не означает, что вы хотите использовать ответ "just-use-a-library", но если вы используете Underscore/Lodash, вы можете использовать .clamp:

_.clamp(yourInput, lowerBound, upperBound);

Итак, чтобы:

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

Вот его реализация, взятая из 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;
}

Кроме того, стоит отметить, что Lodash делает отдельные методы доступными как автономные модули, поэтому, если вам нужен только этот метод, просто установите его без остальной библиотеки:

npm i --save lodash.clamp

Ответ 7

Если вы можете использовать функции стрелок es6, вы также можете использовать метод частичного приложения:

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

Ответ 8

Вы также можете использовать этот повторно используемый номер-зажимный компонент, который возвращает число, значение которого ограничено заданным диапазоном.

Пример:

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

Как это работает:

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

Ответ 9

Мой любимый:

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