5
\$\begingroup\$

The code:

function L(){N=null;E=[N,N];t=this;h=E;t.u=i=>h=[i,h];
t.o=_=>h==E?N:h[+!(h=h[1])];t.e=(i,l)=>h=(l||h)==E?[i, 
E]:[(l||h)[0],t.e(i,(l||h)[1])];t.s=_=>{o="";while(i=t.o())
{o+=i+","}return o}}

For my response to this (old) question: https://codegolf.stackexchange.com/a/196783/72421 (my linked answer has a commented version of the code and some disclaimers about valid inputs and outputs)

I'm looking for suggestions on how to golf it further. I feel the last function is especially verbose. I managed to make every other function a single expression so I didn't need curly brackets or a return statement, but couldn't figure out how to make the last one not require a while loop.

\$\endgroup\$
4
  • \$\begingroup\$ As a side note, I think t.o() fails if the list contains a 0 (or any other falsy value that may actually appear in the list), because it's treated the same way as a null. I assume that you're only asking for a golfed version, bugs included. :) But you may want to clarify this point. \$\endgroup\$
    – Arnauld
    Commented Dec 10, 2019 at 0:23
  • \$\begingroup\$ @Arnauld I mentioned that as a disclaimer on my answer. I'm new, and not sure if that's a violation of the rules. Also wasn't sure if I should copy-paste all that into this question. \$\endgroup\$ Commented Dec 10, 2019 at 0:24
  • \$\begingroup\$ Oh I see. I overlooked the footnote in your answer. \$\endgroup\$
    – Arnauld
    Commented Dec 10, 2019 at 0:26
  • \$\begingroup\$ @Arnauld If someone figured out a better way to do t.o that didn't have that issue (without just replacing +!. with an equality test that adds a few bytes) I'd definitely consider that a valid answer to this question. \$\endgroup\$ Commented Dec 10, 2019 at 0:27

2 Answers 2

8
\$\begingroup\$

I think the best way to get rid of the curly brackets is to go recursive.

Original function (46 bytes)

t.s=_=>{o="";while(i=t.o()){o+=i+","}return o}

Recursive version (29 bytes)

t.s=_=>(i=t.o())?i+[,t.s()]:i

The i+[,t.s()] trick saves a byte over i+','+t.s().

Because you stop when t.o() returns null, the result of your original version always ends with a comma. In the new version, we actually append null at the end (that's the :i) but it's coerced to an empty string because of the above trick, leading to the same behavior.

\$\endgroup\$
3
  • \$\begingroup\$ Thank you! Do you have any suggestions for avoiding h being a global variable without having to replace every usage with t.h? \$\endgroup\$ Commented Dec 10, 2019 at 0:31
  • 1
    \$\begingroup\$ @DanielFranklin You can simply declare function L(h) (an unused parameter) to put h in the local scope. But this is code-golf, so we usually don't worry about that -- unless explicitly specified otherwise but I haven't read the original challenge thoroughly. \$\endgroup\$
    – Arnauld
    Commented Dec 10, 2019 at 0:39
  • \$\begingroup\$ Thank you. Good to know that isn't necessary. \$\endgroup\$ Commented Dec 10, 2019 at 0:42
5
\$\begingroup\$

Shortening t.s

Favor recursion over while loop

Given your t.s function

t.s=_=>{o="";while(i=t.o()){o+=i+","}return o}

Observe that o is a simple accumulator, so we can easily convert the loop into a recursive function. There are several ways to write the recursive function:

// explicit accumulator, aka tail-recursion
t.s=(o="")=>(i=t.o())?t.s(o+i+","):o
// implicit accumulator, shorter, saves 15 bytes from OP's code
t.s=_=>(i=t.o())?i+","+t.s():""

Free commas

i+","+t.s() can be shortened to i+[,t.s()], saving 1 byte.

Shortening the rest

Initialize the second parameter of t.e to h

The function t.e is using (l||h) several times, just to handle the initial call. JS's default argument is very permissive, so we can do this:

// instead of
t.e=(i,l)=>h=(l||h)==E?[i,E]:[(l||h)[0],t.e(i,(l||h)[1])];
// do this
t.e=(i,l=h)=>h=l==E?[i,E]:[l[0],t.e(i,l[1])];

Simplify base case

Instead of E=[N,N], simply E=[] works too. This has several golfing opportunities regarding string coercion:

  • h==E is equivalent to h==[], and [] coerces to "". Anything that stringifies into something other than "" is greater than E, so we can rewrite h==E?A:B into h>E?B:A.
  • h is now a linked list where 3::2::1::nil looks like [3,[2,[1,[]]]], which exactly stringifies into "3,2,1,". So we can simply coerce h to string: t.s=_=>h+"", or even better, t.s=_=>h+E.

Array unpacking

We can slightly do better here too:

// instead of
t.o=_=>h>E?h[+!(h=h[1])]:N;
// do this
t.o=_=>h>E?([a,h]=h,a):N;

And this also applies to t.e:

// instead of this
t.e=(i,l=h)=>h=l>E?[l[0],t.e(i,l[1])]:[i,E];
// do this
t.e=(i,[a,l]=h)=>h=l?[a,t.e(i,l)]:[i,E];

I chose l? because whenever h is nonempty, l is a reference so it always evaluates to true. If h is empty, both a and l become undefined.

Side note: I found that the OP's code actually works with falsy list items, because the only real comparison is h==E, that is, comparing stringification reference of whole array. Whatever E is, h==E cannot be true if the list h has at least one item, since its string will have at least one more comma than E's the reference becomes different.

Final result, 125 121 bytes

function L(){h=E=[];t=this;t.u=i=>h=[i,h];t.o=_=>h>E?([a,h]=h,a):null;t.e=(i,[a,l]=h)=>h=l?[a,t.e(i,l)]:[i,E];t.s=_=>h+E}

Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ Side side note: JavaScript compares arrays by reference, not by string. You're still right I think. You can verify this from the fact that [1,1]==[1,1] is false but [1,1]+""==[1,1]+"" is true \$\endgroup\$ Commented Dec 10, 2019 at 1:07
  • \$\begingroup\$ *compares two arrays \$\endgroup\$ Commented Dec 10, 2019 at 1:22
  • \$\begingroup\$ why not L=()=>{ * insert L's body here * } \$\endgroup\$
    – Citty
    Commented Dec 11, 2019 at 18:01
  • \$\begingroup\$ @famous1622 Because I have to provide a class, and you can't use new to create an instance of an arrow function. Furthermore, this in the arrow function would refer to window because arrow functions don't have their own scope \$\endgroup\$ Commented Dec 11, 2019 at 22:30

Your Answer

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

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