5
\$\begingroup\$

I have an expression that could be expressed as either of :

a += (A ? B ? x : C ? y : D : D);

a += (A && B ? x : A && C ? y : D);

where A,B,C are expressions of 5-10 bytes each, and x and y are single character literals (3-4 bytes). D is another chain of ternaries (without the branching problem).

I'm getting stuck trying to eliminate the duplication of D or A. If I was using if, it would be something like this:

if (A)
    if (B)
        x
    else if (C)
        y
else D

Obviously I could do ((z=A) && B ? x : z && C ? y : D)...but any other more creative suggestions?

The actual code looks something like:

if (r%4<2&&r>3&&c<22&&c>1)
    if ((i-r)%8==6)
        '\\'
    else if ((i+r)%8==1)
        '/'
else

D is something like:

(i+r) % 8 == 3 ? '/' : 
    (c-r+16) % 8 == 4 ? '\\' : 
\$\endgroup\$
6
  • \$\begingroup\$ It would help to know what those expressions are. \$\endgroup\$
    – Leaky Nun
    May 18, 2017 at 3:57
  • \$\begingroup\$ yup, updated. try not to distracted by golfing them :) \$\endgroup\$ May 18, 2017 at 3:58
  • \$\begingroup\$ Well, (i-r)%8 can become i-r&7 :p \$\endgroup\$
    – Leaky Nun
    May 18, 2017 at 3:59
  • \$\begingroup\$ I still can't see what your D is. \$\endgroup\$
    – Leaky Nun
    May 18, 2017 at 4:00
  • \$\begingroup\$ Updated again... \$\endgroup\$ May 18, 2017 at 4:01

2 Answers 2

2
\$\begingroup\$

If you know that x and y cannot contain falsy values, as your code examples suggest, you can do the following to eliminate duplicate evaluation of A or D:

a += A && (B && x || C && y) || D;

Demo code and test cases in the following snippet:

// return x
test(1,1,0); // A and B
test(1,1,1); // A and B (and C)

// return y
test(1,0,1); // A and C

// return D
test(0,0,0); // 
test(0,0,1); // C
test(0,1,0); // B
test(0,1,1); // B and C
test(1,0,0); // A


function test(A, B, C) {
  var x = 'x', y = 'y', D = 'D';
  a = A && (B && x || C && y) || D;
  expected = (A && B ? x : A && C ? y : D);
  var ws = ' ';
  console.log(
    [
      A && 'A' || ws, 
      B && 'B' || ws, 
      C && 'C' || ws
    ].join(ws),
    ' ==> a = ' + a,
    a === expected ? 
      'Passed' : 
      'Failed, expected ' + expected
  );
}

Otherwise, if falsy values are possible, you could do this:

a += [D, x, y][A && (B && 1 || C && 2) || 0];

Demo code and test cases in the following snippet:

// return x
test(1,1,0); // A and B
test(1,1,1); // A and B (and C)

// return y
test(1,0,1); // A and C

// return D
test(0,0,0); // 
test(0,0,1); // C
test(0,1,0); // B
test(0,1,1); // B and C
test(1,0,0); // A


function test(A, B, C) {
  var x = false, y = 0, D = '';
  A = !!A; B = !!B; C = !!C;
  a = [D, x, y][A && (B && 1 || C && 2) || 0];
  expected = (A && B ? x : A && C ? y : D);
  var ws = ' ';
  console.log(
    [
      A && 'A' || ws, 
      B && 'B' || ws, 
      C && 'C' || ws
    ].join(ws),
    ' ==> a = ' + xyD(a, x, y, D),
    a === expected ? 
      'Passed' : 
      'Failed, expected ' + xyD(expected, x, y, D)
  );
}

function xyD(result, x, y, D) {
  return result === x ? 'x' :
         result === y ? 'y' :
         result === D ? 'D' : '<error>' ;
}

\$\endgroup\$
1
  • \$\begingroup\$ Thanks, that's very helpful. So, probably I should just stop thinking in terms of ternaries altogether. \$\endgroup\$ Jun 12, 2017 at 22:23
1
\$\begingroup\$

Since short-circuiting is not required here, you can also do:

d=D;a+=A?B?x:C?y:d:d;

If short-circuiting were required, since your B and C are truthy values, you can do:

a+=(A?B?x:C?y:0:0)||D;

If short-circuiting were required and your B and C are not truthy values:

d=_=>D;a+=A?B?x:C?y:d():d();
\$\endgroup\$
1
  • \$\begingroup\$ Ah, that second one is an interesting way to "fall through" a ternary operator. \$\endgroup\$ May 18, 2017 at 4:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.