web-dev-qa-db-ja.com

自分自身を繰り返さずに三項演算子(別名if)式を書く方法

たとえば、次のようなもの:

var value = someArray.indexOf(3) !== -1 ? someArray.indexOf(3) : 0

それを書くより良い方法はありますか?繰り返しますが、上記の正確な質問への答えを求めているのではなく、三項演算子式で繰り返しオペランドを使用する可能性がある場合の例です...

99
user1354934

個人的には、これを行うための最良の方法は、古き良きifステートメントであると思います。

var value = someArray.indexOf(3);
if (value === -1) {
  value = 0;
}
175
slebetman

コードは読みやすいものでなければならないので、簡潔であることはどんなコストであっても簡潔であることを意味するべきではありません-そのためには、 https://codegolf.stackexchange.com/ に再投稿する必要があります。 indexという名前の変数は、読みやすさを最大化するために(実行時のコストも最小限に抑えています):

var index = someArray.indexOf( 3 );
var value = index == -1 ? 0 : index;

しかし、同僚やプロジェクトの協力者にとって残酷なサディストであるため、この表現を本当に減らしたい場合は、次の4つのアプローチを使用できます。

1:varステートメントの一時変数

varステートメントの機能を使用して、コンマで区切られたときに2番目の一時変数indexを定義(および割り当て)できます。

var index = someArray.indexOf(3), value = index !== -1 ? index: 0;

2:自己実行匿名関数

別のオプションは、自己実行の匿名関数です。

// Traditional syntax:
var value = function( x ) { return x !== -1 ? x : 0 }( someArray.indexOf(3) );

// ES6 syntax:
var value = ( x => x !== -1 ? x : 0 )( someArray.indexOf(3) );

3:カンマ演算子

JavaScriptがサポートする悪名高い「コンマ演算子」もあります。これは、CおよびC++にも存在します。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator

単一の式が必要な場所に複数の式を含める場合は、カンマ演算子を使用できます。

これを使用して、valueに再割り当てすることにより、副作用を導入できます。

var value = ( value = someArray.indexOf(3), value !== -1 ? value : 0 );

これは、var valueが最初に(ステートメントとして)解釈され、then左端、最も内側のvalue割り当て、次に右コンマ演算子の手、次に三項演算子-すべて正当なJavaScript。

4:部分式での再割り当て

コメンテーター@IllusiveBrianは、valueへの割り当てが括弧付きの部分式として使用される場合、コンマ演算子(前の例)の使用は不要であると指摘しました。

var value = ( ( value = someArray.indexOf(3) ) !== -1 ? value : 0 );

論理式での否定の使用は人間にとって従うのが難しい場合があることに注意してください。したがって、上記の例はすべてidx !== -1 ? x : yidx == -1 ? y : xに変更することで読みやすくなります。

var value = ( ( value = someArray.indexOf(3) ) == -1 ? 0 : value );
97
Dai

数字の場合

Math.max()関数を使用できます。

var value = Math.max( someArray.indexOf('y'), 0 );

最初の結果が0より大きい場合は、0からの結果の境界を保持します。 indexOfの結果が-1の場合、-1より大きい0を返します。

ブール値とブール値yの場合

JSの場合、 falsy 値がどのように評価されるかという理由で、特別な一般規則はありません。

しかし、何かがほとんどの場合に役立つ場合は、or演算子(||)です:

// Instead of
var variable = this_one === true ? this_one : or_this_one;
// you can use
var variable = this_one || or_this_one;

最初の例では、indexOf0を返すことができ、0 || -1を評価すると、-1falsy 値であるため、0を返すため、これには非常に注意する必要があります。

53

実際には、別の変数を使用するだけです。

あなたの例はこのようなものに一般化します。

var x = predicate(f()) ? f() : default;

計算された値をテストし、述語を渡す場合にその値を変数に割り当てます。計算値の再計算を避ける方法は明らかです。結果を保存するために変数を使用します。

var computed = f();
var x = predicate(computed) ? computed : default;

私はあなたの言うことを理解します-これを行うには、少しきれいに見える何らかの方法があるはずです。しかし、私はこれを行うのに(イディオム的に)最良の方法だと思います。何らかの理由でコード内でこのパターンを何度も繰り返している場合は、少しのヘルパー関数を作成できます。

var setif = (value, predicate, default) => predicate(value) ? value : default;
var x = setif(someArray.indexOf(3), x => x !== -1, 0)
26
Triptych

編集:ここにあります、 Nullary-coalescing の提案がJavaScriptになりました!


||を使用

const result = a ? a : 'fallback value';

に等しい

const result = a || 'fallback value';

aBooleanにキャストすると、falseが返される場合、result'fallback value'が割り当てられ、そうでない場合はaの値が割り当てられます。


falseresultにキャストするEdgeのケースa === 0に注意してください(誤って)'fallback value'を使用します。自己責任でこのようなトリックを使用してください。


PS。 Swiftなどの言語には nil-coalescing 演算子(??)があり、これは同様の目的を果たします。たとえば、Swiftには、JavaScriptのresult = a ?? "fallback value"に非常に近いconst result = a || 'fallback value';を記述します。

17
Lyubomir

変数リファクタリングの抽出 を使用します。

var index = someArray.indexOf(3);
var value = index !== -1 ? index : 0

constの代わりにvarを使用することをお勧めします。追加の抽出を行うこともできます。

const index = someArray.indexOf(3);
const condition = index !== -1;
const value = condition ? index : 0;

実際には、indexcondition、およびvalueよりも意味のある名前を使用してください。

const threesIndex = someArray.indexOf(3);
const threeFound = threesIndex !== -1;
const threesIndexOrZero = threeFound ? threesIndex : 0;
8
Dave Cousineau

私は個人的に2つのバリアントを好みます:

  1. 純粋な場合、@ slebetmanが提案したように

  2. この例のように、無効な値をデフォルトの値に置き換える別の関数:

function maskNegative(v, def) {
  return v >= 0 ? v : def;
}

Array.prototype.indexOfOrDefault = function(v, def) {
  return maskNegative(this.indexOf(v), def);
}

var someArray = [1, 2];
console.log(someArray.indexOfOrDefault(2, 0)); // index is 1
console.log(someArray.indexOfOrDefault(3, 0)); // default 0 returned
console.log(someArray.indexOfOrDefault(3, 123)); // default 123 returned
6
Iłya Bursov

おそらく合体演算子を探しています。幸いなことに、Arrayプロトタイプを利用してプロトタイプを作成できます。

Array.prototype.coalesce = function() {
    for (var i = 0; i < this.length; i++) {
        if (this[i] != false && this[i] != null) return this[i];
    }
}

[null, false, 0, 5, 'test'].coalesce(); // returns 5

関数にパラメーターを追加することで、これをさらに一般化できます。

Array.prototype.coalesce = function(valid) {
    if (typeof valid !== 'function') {
        valid = function(a) {
            return a != false && a != null;
        }
    }

    for (var i = 0; i < this.length; i++) {
        if (valid(this[i])) return this[i];
    }
}

[null, false, 0, 5, 'test'].coalesce(); // still returns 5
[null, false, 0, 5, 'test'].coalesce(function(a){return a !== -1}); // returns null
[null, false, 0, 5, 'test'].coalesce(function(a){return a != null}); //returns false
6
Tyzoid

@slebetmanの答えが好きです。その下のコメントは、変数が「中間状態」にあることに対する懸念を表しています。これがあなたにとって大きな懸念であれば、関数にカプセル化することをお勧めします:

function get_value(arr) {
   var value = arr.indexOf(3);
   if (value === -1) {
     value = 0;
   }
   return value;
}

それからちょうど電話

var value = get_value( someArray );

他の場所でそれらを使用している場合は、より汎用的な機能を実行できますが、非常に特殊なケースの場合は過剰なエンジニアリングをしないでください。

しかし、正直に言うと、複数の場所から再利用する必要がない限り、@ slebetmanとして実行します。

5
Adam

私はあなたの質問を見るのに2つの方法があります:あなたは行の長さを短くしたい、または三項で変数を繰り返すことを避けたいのです。 1つ目は簡単です(他の多くのユーザーが例を投稿しています)。

var value = someArray.indexOf(3) !== -1 ? someArray.indexOf(3) : 0;

次のように短縮することができます(関数呼び出しを考えると、そうすべきです):

var value = someArray.indexOf(3);
value = value !== -1 ? value : 0;

次のように、3進数の変数の繰り返しを防ぐより一般的なソリューションを探している場合:

var value = conditionalTest(foo) ? foo : bar;

fooは1回だけ表示されます。次の形式のソリューションの破棄:

var cad = foo;
var value = conditionalTest(foo) ? cad : bar;

技術的には正しいが、ポイントが欠落している場合、あなたは運が悪い。求める簡潔な構文を持つ演算子、関数、およびメソッドがありますが、そのような構成体は、定義により三項演算子ではありません。

例:

javascript、||を使用して、LHSがfalseyのときにRHSを返します。

var value = foo || bar; // equivalent to !foo ? bar : foo
4
asgallant

ヘルパー関数を使用します。

function translateValue(value, match, translated) {
   return value === match ? translated : value;
}

これでコードは非常に読みやすくなり、繰り返しはありません。

var value = translateValue(someArray.indexOf(3), -1, 0);

コーディングの問題の階層は次のとおりです。

  1. 正解(真のパフォーマンスまたはSLAの懸念を含む)
  2. クリア
  3. 簡潔な
  4. 速い

これまでのところ、ページ上のすべての回答は正しいように見えますが、私のバージョンは簡潔さよりも重要な最高の明快さを持っていると思います。ヘルパー関数は、再利用できるためカウントしない場合、最も簡潔です。ヘルパー関数を使用するというやや似たような提案は、残念ながらラムダを使用しますが、ラムダはそれが何をしているのかわかりにくくしています。ラムダを使用せず、値だけを使用する1つの目的を持つ単純な関数の方がはるかに優れています。

追伸ES6構文が好きな場合:

const translateValue = (value, match, translated) => value === match ? translated : value;
let value = translateValue(someArray.indexOf(3), -1, 0); // or const
3
ErikE

||演算子はindexOfに合わせて調整できると思います。

var value = ((someArray.indexOf(3) + 1) || 1) - 1;

返される値は1だけ上にシフトされ、-1から0を作成します。これは偽であり、したがって2番目の1に置き換えられます。その後、戻されます。

ただし、繰り返しを避けるよりも読みやすさが優れていることに注意してください。

2
IllidanS4

これは bitwise NOT-1のデフォルト値を使用した単純なソリューションで、後でゼロになります。

index = ~(~array.indexOf(3) || -1);

基本的には、元の値またはデフォルト値を返す二重ビット単位のNOTで機能します。デフォルト値は、ビット単位のNOTを適用するとゼロを返します。

真理値表を見てみましょう。

 indexOf    ~indexOf   boolean    default     value      result         comment
---------  ---------  ---------  ---------  ---------  ---------  ------------------
      -1          0     falsy          -1         -1          0   take default value
       0         -1    truthy                     -1          0
       1         -2    truthy                     -2          1
       2         -3    truthy                     -3          2
2
Nina Scholz

再割り当てを使用できます:

  • 変数を1つの値に初期化します
  • 最初の条件が偽の場合、2番目の式は評価されないため、再割り当てには&&演算子のシリアル化を使用します

例.

var value = someArray.indexOf(3);
value == -1 && (value=0);
var someArray = [4,3,2,1];

var value = someArray.indexOf(1);
value == -1 && (value=0);
console.log('Found:',value);

var value = someArray.indexOf(5);
value == -1 && (value=0);
console.log('Not Found:',value);
0
vol7ron

質問のサンプルコードを考えると、3someArrayのインデックス0に設定されているかどうかがどのように判断されるかは明確ではありません。 .indexOf()から返された-1は、一致する可能性のある推定される不一致を除外するために、このインスタンスで価値があります。

3が配列に含まれていない場合、-1が返されます。 1.indexOf()の結果に追加して、結果が-1であるfalseとして評価できます。ここで、||OR演算子と0が続きます。 valueが参照されている場合、1を減算して、配列または-1の要素のインデックスを取得します。

これは、単に.indexOf()を使用し、if条件で-1をチェックすることにつながります。または、valueundefinedとして定義して、元の参照に関連する評価条件の実際の結果に関する混乱を回避します。

var someArray = [1,2,3];
var value = someArray.indexOf(3) + 1 || 1;
console.log(value -= 1);

var someArray = [1,2,3];
var value = someArray.indexOf(4) + 1 || 1;
// how do we know that `4` is not at index `0`?
console.log(value -= 1);

var someArray = [1,2,3];
var value = someArray.indexOf(4) + 1 || void 0;
// we know for certain that `4` is not found in `someArray`
console.log(value, value = value || 0);
0
guest271314

ターナリはif-elseのようなものです。elseの部分が必要ない場合は、代わりに単一のifを使用してください。

if ((value = someArray.indexOf(3)) < 0) value = 0;
0
Khaled.K