web-dev-qa-db-ja.com

セグメントに数値をキャップする最もエレガントな方法は何ですか?

xa、およびbが数字だとしましょう。 xをセグメント[a, b]の境界にキャップする必要があります。

Math.max(a, Math.min(x, b))は書けますが、読みやすいとは思いません。誰かがこれをより読みやすい方法で書く賢い方法を持っていますか?

100
Samuel Rossille

その方法はかなり標準的です。説明したようなユーティリティclamp関数を定義できます here

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

(拡張言語ビルトインは一般的に眉をひそめていますが)

169

それほど「数学」指向のアプローチではありませんが、この方法でも機能するはずです、</>テストが公開されます(ミニマックスよりも理解しやすいかもしれません)

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

ECMAScript 2017の更新:

Math.clamp(x, lower, upper)

ただし、今日の時点ではステージ1 提案 であることに注意してください。広くサポートされるまで、 polyfill を使用できます。

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

これは「ライブラリを使用するだけ」の答えにはなりませんが、アンダースコア/ロダッシュを使用している場合にのみ使用できます .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
Nobita

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

矢印のセクシーさの精神で、マイクロクランプ/制約/ゲート/&cを作成できます。残りのパラメーターを使用する関数

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

次に、3つの値を渡すだけです

clamp(100,-3,someVar);

それは、再び、もしセクシーなら、あなたは「短い」ということです

3
stoke motor

関数を定義したくない場合は、Math.min(Math.max(x, a), b)のように記述してもそれほど悪くはありません。

2
Ricardo