programing tip

자신을 반복하지 않고 삼항 연산자 (일명 if) 표현식을 작성하는 방법

itbloger 2020. 8. 17. 08:20
반응형

자신을 반복하지 않고 삼항 연산자 (일명 if) 표현식을 작성하는 방법


예를 들면 다음과 같습니다.

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

그것을 작성하는 더 좋은 방법이 있습니까? 다시 말하지만, 저는 위의 정확한 질문에 대한 답을 찾고 있지 않습니다. 삼항 연산자 표현식에서 피연산자를 반복했을 때의 예일뿐입니다.


개인적으로이 작업을 수행하는 가장 좋은 방법은 여전히 ​​좋은 오래된 if진술입니다.

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

코드는 읽을 수 있어야 그렇게되고 간결해야하는 비용이 어떤되지 평균 존재의 간결한 - 당신이 다시 게시해야 그것에 대해 https://codegolf.stackexchange.com/ - 그래서 대신 내가라는 이름의 두 번째 지역 변수를 사용하는 것이 좋습니다 것입니다 index(읽기 이해도를 극대화하기 위해 최소한의 런타임 비용으로도 언급합니다) :

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

하지만 동료 나 프로젝트 공동 작업자에게 잔인한 가학 주의자이기 때문에이 표현을 정말로 줄이고 싶다면 다음과 같은 4 가지 접근 방식을 사용할 수 있습니다.

1 : var명령문의 임시 변수

var명령문의 기능을 사용 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(그것이 문이다로) 먼저 해석하고, 그 다음 가장 왼쪽에, 가장 안쪽 value할당 한 다음 쉼표 연산자의 오른쪽, 다음 삼항 연산자 - 모든 법적 자바 스크립트.

4 : 하위 표현식에서 재 할당

해설자 @IllusiveBrian은 할당 value이 괄호로 묶인 하위 표현식으로 사용되는 경우 쉼표 연산자 (이전 예에서)의 사용이 필요하지 않다고 지적했습니다 .

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

논리식에서 음수를 사용하는 것은 사람이 따라 가기가 더 어려울 수 있습니다. 따라서 위의 모든 예제는 다음으로 변경 idx !== -1 ? x : y하여 읽기를 단순화 할 수 있습니다 idx == -1 ? y : x.

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

숫자

Math.max()기능을 사용할 수 있습니다 .

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

경우 0보다 첫 번째 결과가 더 커질 때까지 결과의 경계를 유지합니다 0. 그리고의 결과 indexOf가 인 -1경우보다 크므로 0을 반환 -1합니다.

부울 및 부울 y 값

JS의 경우 거짓 값이 평가되는 방식 때문에 특별히 일반적인 규칙 AFAIK가 없습니다 .

그러나 대부분의 경우 도움이 될 수있는 것이 or 연산자 ( ||) 인 경우 :

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

당신은, 때문에 첫 번째 예에서,이 매우 조심해야 indexOf반환 할 수 있습니다 0당신이 평가되는 경우 0 || -1가 반환 -1하기 때문에 0A는 falsy 값.


실제로는 다른 변수를 사용하십시오.

귀하의 예는 다음과 같이 일반화됩니다.

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)

편집 : 여기 에 JavaScript에서 Nullary-coalescing 제안이 있습니다 !


사용하다 ||

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

다음과 같다

const result = a || 'fallback value';

캐스팅 경우 aBoolean반환 false, result할당됩니다 'fallback value'의 다른 값을 a.


가장자리 케이스주의 a === 0에 캐스트, falseresult(잘못) 소요됩니다 'fallback value'. 자신의 책임하에 이와 같은 트릭을 사용하십시오.


추신. Swift와 같은 언어에는 유사한 목적으로 사용되는 nil-coalescing 연산자 ( ??)가 있습니다. 예를 들어, Swift에서는 result = a ?? "fallback value"JavaScript에 매우 가깝게 작성합니다.const result = a || 'fallback value';


사용하여 추출 변수 리팩토링을 :

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;

실제로,보다 더 의미있는 이름을 사용 index, condition하고 value.

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

통합 연산자를 찾고있을 것입니다. 운 좋게도 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

This could be further generalized to your case, by adding a parameter to the function:

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

I personally prefer two variants:

  1. Pure if, like @slebetman suggested

  2. Separate function, which replaces invalid value with default one, like in this example:

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


I like @slebetman's answer. The comment under it express concern about the variable being in an "intermediate state". if this is a big concern for you then I suggest encapsulating it in a function:

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

Then just call

var value = get_value( someArray );

You could do more generic functions if you have uses for them in other places, but don't over-engineer if it's a very specific case.

But to be honest I would just do as @slebetman unless I needed to re-use from several places.


There are two ways I can see of looking at your question: you either want to reduce line length, or you specifically want to avoid repeating a variable in a ternary. The first is trivial (and many other users have posted examples):

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

can be (and should be, given the function calls) shortened like so:

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

If you are looking for a more generic solution that prevents the repetition of a variable in a ternary, like so:

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

where foo only appears once. Discarding solutions of the form:

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

as technically correct but missing the point, then you are out of luck. There are operators, functions, and methods that possesses the terse syntax you seek, but such constructs, by definition, aren't ternary operators.

Examples:

javascript, using || to return the RHS when the LHS is falsey:

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

Use a helper function:

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

Now your code is very readable, and there's no repetition.

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

The hierarchy of coding concerns is:

  1. Correct (including true performance or SLA concerns)
  2. Clear
  3. Concise
  4. Fast

All the answers on the page so far appear to be correct, but I think my version has the highest clarity, which is more important than conciseness. If you don't count the helper function—as it can be reused—it is the most concise as well. The somewhat similar suggestion to use a helper function unfortunately uses a lambda that, to me, just obscures what it's doing. A simpler function with one purpose that doesn't take a lambda, just values, is to me much better.

P.S. If you like ES6 syntax:

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

I think the || operator can be tailored to indexOf:

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

The returned value is shifted up by 1, making 0 from -1, which is falsey and therefore gets replaced by the second 1. Then it is shifted back.

However, please keep in mind that readability is superior to avoiding repetition.


This is a simple solution with bitwise NOT and a default value of -1 which results later to zero.

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

It works basically with a double bitwise NOT, which returns the original value or a default value, which after applying bitwise NOT returns zero.

Let's have a look to the table of truth:

 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

You could use re-assignment:

  • initialize variable to one value
  • use the serialization of the && operator for reassignment, because if the first condition is false, the second expression won't be evaluated

Ex.

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);


Given the example code at Question it is not clear how it would be determined that 3 is or is not set at index 0 of someArray. -1 returned from .indexOf() would be valuable in this instance, for the purpose of excluding a presumed non-match which could be a match.

If 3 is not included in array, -1 will be returned. We can add 1 to result of .indexOf() to evaluate as false for result being -1, where followed by || OR operator and 0. When value is referenced, subtract 1 to get index of element of array or -1.

Which leads back to simply using .indexOf() and checking for -1 at an if condition. Or, defining value as undefined to avoid possible confusion as to actual result of evaluated condition relating to original reference.

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);


A ternary is like an if-else, if you don't need the else part, why not just a single if instead..

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

For this particular case, you could use short-circuiting with the logical || operator. As 0 is considered falsy, you can +1 to your index, thus, if index+1 is 0 then you'll get the right-hand side of the return as your result, otherwise, you'll get your index+1. You can then -1 from this result to get your index:

const someArray = [1, 2, 3, 4];
const v = ((someArray.indexOf(3)+1) || 1)-1;
console.log(v);

참고URL : https://stackoverflow.com/questions/43359734/how-to-write-a-ternary-operator-aka-if-expression-without-repeating-yourself

반응형