Скажімо x
, a
і b
це числа. Мені потрібно обмежувати x
межі сегмента [a, b]
.
Я можу писати Math.max(a, Math.min(x, b))
, але я не думаю, що це дуже легко читати. Хтось має розумний спосіб написати це більш читабельним способом?
Скажімо x
, a
і b
це числа. Мені потрібно обмежувати x
межі сегмента [a, b]
.
Я можу писати Math.max(a, Math.min(x, b))
, але я не думаю, що це дуже легко читати. Хтось має розумний спосіб написати це більш читабельним способом?
Відповіді:
Те, як ви це робите, досить стандартне. Ви можете визначити функцію утиліти 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);
};
(Хоча вбудовані мови розширення мови, як правило, нахмурені)
Math.min
та Math.max
не має значення, поки параметр Math.min
є max
та параметр Math.max
є min
.
Number.prototype
в даному випадку) недоцільно з різних причин. Див. "Погана практика: розширення нативних прототипів" на сайті developer.mozilla.org/en-US/docs/Web/JavaScript/…
менш орієнтований на "Математику" підхід, але він також повинен працювати, таким чином, тест викритий (можливо, більш зрозумілий, ніж мінімаксування), але це дійсно залежить від того, що ви маєте на увазі під "читабельним"
function clamp(num, min, max) {
return num <= min ? min : num >= max ? max : num;
}
Math.random()
дзвінка, цей простий підхід на 10 разів швидший .
Оновлення для ECMAScript 2017:
Math.clamp(x, lower, upper)
Але зауважте, що на сьогоднішній день це пропозиція першого етапу . Поки вона не отримає широкої підтримки, ви можете використовувати полів .
Це не хоче бути відповіддю "просто використовувати бібліотеку", але лише у випадку, коли ви використовуєте Lodash, ви можете використовувати .clamp
:
_.clamp(yourInput, lowerBound, upperBound);
Так що:
_.clamp(22, -10, 10); // => 10
Ось його реалізація, взята з джерела Lodash :
/**
* 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;
}
Крім того, варто зазначити, що Лодаш робить окремі методи доступними як окремі модулі, тому, якщо вам потрібен лише цей метод, ви можете просто встановити його без іншої частини бібліотеки:
npm i --save lodash.clamp
Якщо ви можете використовувати функції стрілок 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
У дусі сексуальності стріли ви могли б створити мікро-затискач / обмеження / ворота / & c. функція за допомогою параметрів спокою
var clamp = (...v) => v.sort((a,b) => a-b)[1];
Потім просто переведіть три значення
clamp(100,-3,someVar);
Тобто, знову ж таки, якщо під сексуальним, ви маєте на увазі "короткий"
clamp
, perf спричинить серйозний удар, якщо у вас складна логіка (навіть якщо це "сексуально")
Це розширює потрійний варіант на if / else, який мінімізується, еквівалентно потрійному варіанту, але не приносить шкоди для читання.
const clamp = (value, min, max) => {
if (value < min) return min;
if (value > max) return max;
return value;
}
Мінімізується до 35b (або 43b, якщо використовується function
):
const clamp=(c,a,l)=>c<a?a:c>l?l:c;
Крім того, залежно від того, яким інструментом чи браузером ви користуєтеся, ви отримуєте різні результати, чи швидша реалізація на основі математики, так і потрійна реалізація. У випадку приблизно однакової продуктивності я б вирішив читати.
Мій улюблений:
[min,x,max].sort()[1]
[1,5,19].sort()[1]
повертає 19. Це можна виправити так: [min,x,max].sort(function(a, b) { return a - b; })[1]
але це вже не сексуально. Окрім випадків, коли широко використовується, може бути проблемою продуктивності для створення нового масиву просто для порівняння трьох чисел.
[min, x, max].sort((a,b) => a-b)[1]