18
\$\begingroup\$

In Java/.NET/C/JavaScript/etc. you can use ternary-ifs to shorten if-statements.

For example (in Java):

// there is a String `s` and an int `i`
if(i<0)s="Neg";else if(i>0)s="Pos";else s="Neut";

Can be shortened with a ternary-if to:

s=i<0?"Neg":i>0?"Pos":"Neut";

Challenge:

Input: A regular if-else (possible with nesting) that sets a single variable.

Output: The converted ternary-if.

Challenge rules:

  • You can assume all if-else cases are possible without brackets (so each if/else-if/else block has a single body).
  • You can assume there won't be any spaces, tabs, or new-lines, except for a single space after each else (including at else if).
  • You can assume the variable names used are always a single lowercase letter ([a-z]).
  • The values given to the variables can be one of:
    • Strings (without spaces/tabs/new-lines), which will be surrounded by double-quotes (i.e. "Test", "SomeString", "Example_string", etc.). You can assume the strings will never contain the substrings if or else, nor will it contain spaces, tabs, newlines, (escaped) double-quotes, or the character =. It can contain the characters ><(){}[];?:!&|, but will be in the printable ASCII range only (['!' (33), '~' (126)]).
    • Integers (i.e. 0, 123, -55, etc.)
    • Decimals (i.e. 0.0, 0.123, -55.55, etc.)
  • The values won't ever be mixed. So all variables assigned are integers, and not some are integers and some are strings.
  • The conditions within parenthesis can contain the following characters =<>!+-/*%&|[], a-z, 0-9. You can assume there won't be any inner parenthesis, and you can also assume there won't be any (confusing) fields of more than one character used (like if(if<0)).
  • You can assume there won't be any short-cuts like i*=10 instead of i=i*10.
  • You won't have to handle dangling else cases, so all if can be paired up with an else. I.e. if(a)if(b)r=0;else r=1; isn't a possible input-case. if(a)if(b)r=0;else r=1;else r=2; or if(a&&b)r=0;else if(a&&!b)r=1;else r=-1; are however.
  • I/O is flexible. Input and Output can be a string, list of characters, read from STDIN, output to STDOUT, etc. Your call.
  • All ternaries will have a right associativity, as is the standard in most languages (but not in for example PHP).

General rules:

  • This is , so shortest answer in bytes wins.
    Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
  • Standard rules apply for your answer, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters and return-type, full programs. Your call.
  • Default Loopholes are forbidden.
  • If possible, please add a link with a test for your code.
  • Also, please add an explanation if possible.

Test cases:

Input:   if(i<0)s="Neg";else if(i>0)s="Pos";else s="Neut";
Output:  s=i<0?"Neg":i>0?"Pos":"Neut";

Input:   if(i%2<1)r=10;else r=20;
Output:  r=i%2<1?10:20;

Input:   if(n<10)if(m<0)i=0;else i=10;else if(m<0)i=-1;else i=1;
Output:  i=n<10?m<0?0:10:m<0?-1:1;

Input:   if(i==1)i=0.0;else i=0.25;
Output:  i=i==1?0.0:0.25;

Input:   if(!a)if(b)r=0;else r=1;else r=2;
Output:  r=!a?b?0:1:2;

Input:   if(a)if(b)r=0;else r=1;else if(c)r=2;else r=3;
Output:  r=a?b?0:1:c?2:3;

Input:   if(a&&b)r=0;else if(a&&!b)r=1;else r=-1;
Output:  r=a&&b?0:a&&!b?1:-1;

Input:   if(i[0]>0)if(j>0)if(q>0)r="q";else r="j";else r="i";else r="other";
Output:  r=i[0]>0?j>0?q>0?"q":"j":"i":"other";

Input:   if(i>0)r="i";else if(j>0)r="j";else if(q>0)r="q";else r="other";
Output:  r=i>0?"i":j>0?"j":q>0?"q":"other";

Input:   if(a>0)if(a<2)x="one";else if(a<3)x="two";else if(a<4)x="three";else x="other";else x="other";
Output:  x=a>0?a<2?"one":a<3?"two":a<4?"three":"other":"other";

Input:   if(b[0]<=b[1])q=5;else if(b[0]==null)q=0;else q=-10;
Output:  q=b[0]<=b[1]?5:b[0]==null?0:-10;
\$\endgroup\$
  • \$\begingroup\$ Technically, in F# if ... then ... else is the ternary operator. So if you write let result = if 10 > 100 then 99 else -99 then the value of result would be -99. \$\endgroup\$ – Ciaran_McCarthy Oct 9 '18 at 15:27
  • 1
    \$\begingroup\$ @Ciaran_McCarthy I would expect that to be the case for most, if not all functional leaning languages that have conditional expressions as the default. Clojure, Scala, and Haskell are the same. \$\endgroup\$ – Carcigenicate Oct 9 '18 at 16:51
  • \$\begingroup\$ @tsh Oops.. I shouldn't add test cases late in the evening after a day of work.. Fixed. \$\endgroup\$ – Kevin Cruijssen Oct 10 '18 at 8:30
  • 2
    \$\begingroup\$ JavaScript Compressor Closure Compiler works great on all these testcases. Which when taking the given inputs would just generate the expected outputs. But it seems that I cannot claim it as an answer. So I would like to comment here. \$\endgroup\$ – tsh Oct 10 '18 at 9:37
5
\$\begingroup\$

Retina 0.8.2, 32 bytes

+r`if.(.*?)\)(.=)
$2$1?
;.{6}=
:

Try it online! Explanation:

r`if.(.*?)\)(.=)
$2$1?

Handle an if immediately before an assignment by moving the assignment before the condition and appending a ?. The stage is matched right-to-left to ensure we get the if closest to the assignment, while the \) ensures that we don't match else by mistake.

+

Repeat the stage to take care of nested ifs.

;.{6}=
:

Any remaining assignments are elses so replace the ;else ?= with a :.

\$\endgroup\$
  • \$\begingroup\$ @nwellnhof Thanks for pointing that out; I thought I was golfing a byte off there because it worked on the test cases. \$\endgroup\$ – Neil Oct 9 '18 at 22:44
6
\$\begingroup\$

Python 2, 126 121 120 114 100 bytes

lambda s:findall(' (.=)',s)[0]+sub('if.(.*?)\)(.=)?',r'\1?',sub('.{5} (.=)?',':',s))
from re import*

Try it online!


Saved:

  • -1 byte, thanks to Kevin Cruijssen
\$\endgroup\$
  • \$\begingroup\$ @KevinCruijssen Thanks :) \$\endgroup\$ – TFeld Oct 9 '18 at 11:22
  • 1
    \$\begingroup\$ Why is the function definition before the import? \$\endgroup\$ – Skyler Oct 9 '18 at 17:51
  • \$\begingroup\$ @Skyler It doesn't actually matter, but it's easier to put the assignment in the header this way \$\endgroup\$ – Jo King Oct 9 '18 at 21:51
6
\$\begingroup\$

Perl 5 -p, 50 49 48 bytes

s/if.(.*?)\)(.=)/\2\1?/g;s/.if./?/g;s/;.{6}=/:/g

Try it online!

The 48 byte version is inspired by Neil's Retina answer.

Explanation

# Replace "if(e1)if(e2)x=" with "x=e1)if(e2?"
s/if.(.*?)\)(.=)/\2\1?/g;
# Replace ")if(" with "?"
s/.if./?/g;
# Replace ";else x=" with ":"
s/;.{6}=/:/g

Old 49 byte solution

s/.{5} (.=)?/:/g;s/if.(.*?)\)(.=)?/\1?/g;$_=$2.$_
\$\endgroup\$
3
\$\begingroup\$

Ruby, 72 71 bytes

->s{$a=$2while s.gsub!(/if.(.*?)\)(.=)?(.*?);\w* (.=)?/,'\1?\3:');$a+s}

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Either ;else or else can be .{5} to save a byte. \$\endgroup\$ – Kevin Cruijssen Oct 9 '18 at 12:58
  • 1
    \$\begingroup\$ Thanks, I found something different with the same effect. \$\endgroup\$ – G B Oct 9 '18 at 13:03
3
\$\begingroup\$

Java (JDK), 119 116 bytes

Almost entirely pure regex solution, chopped and changed a bit from a couple of the other answers.

-3 bytes thanks to some more regex trickery from Kevin

s->s.replaceAll(".*(.=).*","$1$0").replaceAll("if.(.*?)\\)","$1?").replaceAll("([ ?]).=","$1").replace(";else ",":")

Try it online!

Explanation

s->                                         // Lambda function taking a String
   s.replaceAll(".*(.=).*","$1$0")          // Find assigned variable and append to start of String
    .replaceAll("if.(.*?)\\)","$1?")        // Replace any 'if' statements with their condition
                                            // followed by '?'
    .replaceAll("([? ]).=","$1")            // Remove all assignments after a '?' or space
    .replace(";else ",":");                 // Simple replace (no regex) to remove 'else' statements
\$\endgroup\$
  • 1
    \$\begingroup\$ I like the ".*(.=).*","$1$0" you've used, it's 1 byte shorter than the "^(.*)(.=)","$2$1" I had in mind. :) Anyway, you can save 2 bytes changing if\\( to if. and an additional byte changing (\\?| ) to ([? ]). Try it online 116 bytes. \$\endgroup\$ – Kevin Cruijssen Oct 9 '18 at 18:47
  • \$\begingroup\$ @KevinCruijssen Cheers! I spent so long trying to whittle the regex down, I can't believe I missed that! \$\endgroup\$ – Luke Stevens Oct 9 '18 at 19:59
3
\$\begingroup\$

Kakoune v2018.09.04, 43 38 37 bytes

xs\w=(?!=)<ret>d<a-h>Psif.<ret>df);r?xs;else<space><ret>c:<esc>

Explanation:

Kakoune is a multiple selection based, modal editor, inspired by Vim.

  1. x select the whole line

  2. s ... <ret> filter the selection with the regular expression \w=(?!=), which matches all variable assignments, and doesn't match == comparisons

  3. d delete each selection and put its contents in the default register

  4. <a-h> extend all selections to the beginning of their line

  5. P paste the content of the default register before each selection

  6. s ... <ret> filter the selection with the regular expression if.

  7. d delete each selection

  8. f extend each selection forward to the next )

  9. ; reduce each selection to its cursor

  10. r replace each character of each selection with ?

  11. x select the whole line

  12. s ... <ret> filter the selection with ;else<space>

  13. c ... <esc> clear each selection and replace it with :

animation of the code on a test case:

Code In Action

\$\endgroup\$
  • 1
    \$\begingroup\$ Hmm, I've never heard of Kakoune before. I guess there isn't any online compiler for it? If not, could you perhaps add some screenshots of some of the test cases so I can verify it works as intended? Also, if this is your language, you could contact Dennis in the talk.tryitonline.net chat to ask if he could add it to TIO. \$\endgroup\$ – Kevin Cruijssen Oct 9 '18 at 15:57
  • 1
    \$\begingroup\$ @KevinCruijssen I added a gif of one of the test cases. It works on all of them, but making the gifs isn't trivial. \$\endgroup\$ – Vaelus Oct 9 '18 at 17:45
  • \$\begingroup\$ Thanks for the explanation and gif, +1 from me. :) Always nice to learn about a new language. \$\endgroup\$ – Kevin Cruijssen Oct 9 '18 at 18:39
2
\$\begingroup\$

Clean, 386 375 216 196 189 bytes

Look ma, no regex!

import StdEnv,Data.List
?[_,'=':b]= $b
?b= $b
$['if(':s]#(h,[_:t])=span((<>)')')s
=h++['?': ?t]
$[';else ':s]=[':': ?s]
$[a:b]|b>[]=[a: $b]=b
@s=hd[[v,e: $s]\\['else ',v,e=:'=':_]<-tails s]

Try it online!

\$\endgroup\$
1
\$\begingroup\$

JavaScript (Node.js), 80 bytes

s=>(p=s.replace(/(?:if.(.*?)\)|;.*? )(.=)?/g,(_,t,v)=>(V=v||V,t)?t+'?':':'),V+p)

Try it online!

Thanks to Kevin Cruijssen, 2 bytes saved.

\$\endgroup\$
  • \$\begingroup\$ if\( can be if. and ;else can be ;.{5} to save 2 bytes \$\endgroup\$ – Kevin Cruijssen Oct 10 '18 at 7:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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