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\$ Commented May 18, 2017 at 3:57
  • \$\begingroup\$ yup, updated. try not to distracted by golfing them :) \$\endgroup\$ Commented May 18, 2017 at 3:58
  • \$\begingroup\$ Well, (i-r)%8 can become i-r&7 :p \$\endgroup\$ Commented May 18, 2017 at 3:59
  • \$\begingroup\$ I still can't see what your D is. \$\endgroup\$ Commented May 18, 2017 at 4:00
  • \$\begingroup\$ Updated again... \$\endgroup\$ Commented 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\$ Commented 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\$ Commented May 18, 2017 at 4:25

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.