17
\$\begingroup\$

Create a function (or closest equivalent, or full program) that takes an list of some datatype (your choice) that may be nested and a string (in either order), and generalizes the lisp c[ad]+r functions.

Functions are provided which perform compositions of up to four car and cdr operations. Their names consist of a C, followed by two, three, or fourany positive number occurrences of A or D, and finally an R. The series of A's and D's in each function's name is chosen to identify the series of car and cdr operations that is performed by the function. The order in which the A's and D's appear is the inverse of the order in which the corresponding operations are performed.

(source: common lisp hyperspec)

The car and cdr operations will return the first element and all the other elements, respectively, for the purposes of this challenge. The string will hold the operation you should perform.

Examples:

   Array    ,  Accessor  =>  Result
===================================
     [0,1,2],      'cdr' => [1,2]
 [0,[1,2],3],     'cadr' => [1,2]
 [[[[[0]]]]],   'caaaar' => [0]
          [],      'cdr' => do not need to handle (no cdr)
          [],      'car' => do not need to handle (no car)
    anything, 'cr'/'asd' => do not need to handle (invalid command)
         [0],      'car' => 0
         [0],      'cdr' => []

Reference Implementation

{

  const inp = document.getElementById("inp");
  const out = document.getElementById("out");
  inp.onchange = () => {
    const data = JSON.parse(inp.value);
    var list = data.list;
    data.cmd.match(/^c([ad]+)r$/)[1]
      .split("").reverse().forEach(letter =>
        list = letter === "a" ? list[0] : list.slice(1));
    out.value = JSON.stringify(list);
  };
  inp.onchange();

}
<textarea id="inp" rows="2" cols="50">
{ "cmd": "cadadr",
  "list": [0,[1,[2,3],4],5] }
</textarea>
<br>
<textarea readonly id="out" rows="1" cols="50">
waiting, there seems to be a problem
</textarea>

This is , shortest solution in bytes per language wins.

\$\endgroup\$
9
  • \$\begingroup\$ Sandboxed \$\endgroup\$
    – Wezl
    Mar 25 at 14:32
  • 1
    \$\begingroup\$ Would (cadr [0,[1,2],3]) not give [1,2] since (cdr [0,[1,2],3]) is [[1,2],3] and then (car [[1,2],3]) is [1,2]? \$\endgroup\$
    – hyper-neutrino
    Mar 25 at 14:48
  • \$\begingroup\$ So cadr would be cdr then car, or car then cdr? \$\endgroup\$ Mar 25 at 14:50
  • 1
    \$\begingroup\$ @RedwolfPrograms "The order in which the A's and D's appear is the inverse of the order in which the corresponding operations are performed." so (cadr x) is (car (cdr x)) \$\endgroup\$
    – hyper-neutrino
    Mar 25 at 14:52
  • 2
    \$\begingroup\$ Here is something related in real life. Code which generates the cadr functions in C, to a depth of 5, from caar to cdddddr. Generated code here and here. \$\endgroup\$
    – Kaz
    Mar 25 at 23:52

19 Answers 19

13
\$\begingroup\$

JavaScript (V8), 48 bytes

a=>f=b=>b[2]?b[[x,...r]=f(b.slice(1)),1]<f?x:r:a

Try it online!

-2 bytes thanks to @Arnauld!

\$\endgroup\$
2
  • \$\begingroup\$ I'm out of votes for the day, remind me to upvote this later :p \$\endgroup\$ Mar 25 at 15:28
  • 1
    \$\begingroup\$ 48 bytes \$\endgroup\$
    – Arnauld
    Mar 25 at 17:02
11
\$\begingroup\$

Python 3, 68 66 54 bytes

lambda r,s:eval(s[:0:-1].translate(["[1:]","[0]"]*51))

Try it online!

Alt, similar idea (which works in Python 2):

Python 3, 68 66 bytes

lambda l,c:eval(l+''.join("[[10:]]"[x<'d'::2]for x in c[-2:0:-1]))

Try it online!

Both create an eval string which just appends the desired sequence of subscripts/slices directly to the list, with the first one using the added trick of keeping the "r" as the list name. The first one takes an actual list as input and the second takes a string representation of a list.

Credit to xnor for pointing me at translate() and the idea of using r as the list name for -12 bytes!

\$\endgroup\$
7
\$\begingroup\$

Jelly, 11 9 bytes

Oị⁾ḢḊḊṖUv

Try it online!

-2 bytes thanks to Unrelated String!

Takes the accessor on the left and the array on the right

Oị⁾ḢḊḊṖUv - Main link. Accessor A on left, Array L on right
O         - Convert A to ordinals. Note that 'a' is odd and 'd' is even
 ị⁾ḢḊ     - Index into "ḢḊ". Odd characters yield "Ḣ" and even "Ḋ"
     ḊṖ   - Remove first and last values from A
       U  - Reverse
        v - Evaluate as Jelly code, with L as the argument

is the head command, which returns the first element of a list. is the dequeue command, which removes the first element of a list. The code executed by v is just a series of and atoms, which perform one after another.

\$\endgroup\$
5
  • \$\begingroup\$ I'm just gonna assume this aHdDyDPUvs the input, in which case this is self-explanatory. \$\endgroup\$
    – Wezl
    Mar 25 at 15:09
  • 1
    \$\begingroup\$ @Wezl Yeah, it's a well know Jelly program, to aHdDyDPUv the input :) Explanation added \$\endgroup\$ Mar 25 at 15:10
  • 1
    \$\begingroup\$ -2 by cutting out y \$\endgroup\$ Mar 26 at 16:30
  • 1
    \$\begingroup\$ @UnrelatedString Very nice, thanks! \$\endgroup\$ Mar 26 at 16:34
  • \$\begingroup\$ Stole the insight from Jonathan Allan outgolfing me 🙃 \$\endgroup\$ Mar 26 at 16:38
6
\$\begingroup\$

Factor, 61 57 bytes

[ rest reverse rest [ 97 = [ first ] [ rest ] if ] each ]

Try it online!

-4 bytes thanks to @Neil!

Explanation:

This is a quotation (anonymous function) that takes two sequences from the data stack and leaves one sequence on the data stack. In Factor, strings are just sequences of unicode code points and can be manipulated like any other sequence.

  • Given input { 0 { 1 2 } 3 } "cadr"...
  • rest take everything but the first element of a sequence { 0 { 1 2 } 3 } "adr"
  • reverse reverse a sequence { 0 { 1 2 } 3 } "rda"
  • rest take everything but the first element of a sequence { 0 { 1 2 } 3 } "da"
  • [ ... ] each for each element in the sequence...
  • At the beginning of the first iteration, the data stack looks like this: { 0 { 1 2 } 3 } 100
  • 97 push 97 on the data stack { 0 { 1 2 } 3 } 100 97
  • = test top two objects on the data stack for equality { 0 { 1 2 } 3 } f
  • [ first ] [ rest ] if run first quotation if TOS is t, otherwise run the second { { 1 2 } 3 }
  • Now the next iteration of each will kick in and put the next command on the data stack { { 1 2 } 3 } 97
  • Etc.
\$\endgroup\$
2
  • 1
    \$\begingroup\$ but-last reverse can be reverse rest to save four bytes. \$\endgroup\$
    – Neil
    Mar 26 at 10:14
  • \$\begingroup\$ @Neil Clever, thanks! \$\endgroup\$
    – chunes
    Mar 26 at 10:27
5
\$\begingroup\$

Racket, 86 bytes

(λ(a c)(foldr(λ(c a)(case c[(#\a)(car a)][(#\d)(cdr a)][else a]))a(string->list c)))

Try it online!

-3 bytes thanks to Wezl
-73 bytes thanks to ASCII-only
-8 bytes thanks to MLavrentyev

Input in the format (f <data> <string>)

Of course there has to be a lisp/scheme/racket/whatever answer :P

This is probably pretty bad because it's my first time golfing in Racket. I just know what I was taught in my basic first-year CS courses :P

\$\endgroup\$
15
  • \$\begingroup\$ So which one function do you use, and what's the argument order? \$\endgroup\$
    – Wezl
    Mar 25 at 18:31
  • \$\begingroup\$ @Wezl f, and the data comes first, then the string \$\endgroup\$
    – hyper-neutrino
    Mar 25 at 18:33
  • \$\begingroup\$ You can remove the newline, string=? can become equal? or maybe eqv?, I'll see if there are generic substitutes for string-length and substring. If not, some bytes may be saved by taking a list instead of a string or converting the string to a list. \$\endgroup\$
    – Wezl
    Mar 25 at 18:35
  • 3
    \$\begingroup\$ understandable, let's work on removing every shred of good style and readability. :) \$\endgroup\$
    – Wezl
    Mar 25 at 18:38
  • 1
    \$\begingroup\$ @MLavrentyev that would've been nice to know when i was doing lambda calculus for my cs class in racket, lol. thanks! \$\endgroup\$
    – hyper-neutrino
    Mar 28 at 20:37
4
\$\begingroup\$

Python 3, 86 bytes

lambda l,c,a=lambda x:x[0],d=lambda x:x[1:]:eval("(".join(d(c))[:-1]+l+")"*(len(c)-2))

Try it online!

-1 byte thanks to @Stephen

\$\endgroup\$
2
  • 1
    \$\begingroup\$ 86 bytes by re-using your d lambda \$\endgroup\$
    – Stephen
    Mar 25 at 15:04
  • \$\begingroup\$ @Stephen That's clever. Thanks! \$\endgroup\$
    – hyper-neutrino
    Mar 25 at 15:18
4
\$\begingroup\$

Scala, 60 bytes

_.tail.init.:\(_){case(x,m:Seq[_])=>if(x<98)m(0)else m.tail}

Try it in Scastie!

I hate nested lists. Because of them, we need a pattern matching function (or casts, which are longer).

_                            //The command ("caadddaddaar")
  .tail                      //Drop the 'c'
  .init                      //Drop the 'r'
.:\                          //Fold right the "aadddada"
  (_)                        //Starting with the inputted list
  {                          //Pattern matching function literal
    case (x, m: Seq[_]) =>   //The command is x, the list is m (must be a Seq)
    if (x < 98) m(0)         //If the command is 'a', return the first element
    else m.tail              //Else, drop the first element
  }
\$\endgroup\$
4
\$\begingroup\$

J, 35 bytes

4 :0
".'y',~(}.}:x)rplc;:'a{.d}.'
)

Try it online!

Note: -3 off TIO count for f=:

  • Drop the first and last element from the c[ad]+r directive with }.}:x, leaving us with a string of as and ds.
  • Replace every a with {. and every d with }., J's version of car and cdr: rplc;:'a{.d}.'
  • Append the nested array we want to evaluate 'y',~.
  • And evaluate it "..
\$\endgroup\$
3
\$\begingroup\$

JavaScript (V8), 77 72 bytes

c=>d=>[...c.slice(1)].reverse(d=[d]).map(n=>d=n=="d"?d.slice(1):d[0])&&d

Turns out the boring solution wins

JavaScript (V8), 91 90 87 84 bytes

c=>d=>[...c.slice(1)].map(n=>x=>n=="d"?x.slice(1):x[0]).reduceRight((a,f)=>f(a),[d])

Can't add a TIO link on school WiFi :/

Explanation:

This is a cool approach, using functional stuff. It slices the command name to remove the c, splits it into characters, then maps them to functions:

  • d becomes x=>x.slice(1)
  • a and r become x=>x[0]

My current approach actually returns one function, which can still access the n variable, which saves three bytes. I don't really know how to explain it but it works :p

It then uses reduceRight to apply those functions in reverse order, on [d]. This saves a byte over my old approach, which also sliced off the r.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ How do you post solutions from your school? I am curious to know \$\endgroup\$
    – wasif
    Mar 25 at 16:09
  • \$\begingroup\$ @Wasif The same way I would at home, minus TIO \$\endgroup\$ Mar 25 at 16:31
  • 1
    \$\begingroup\$ no, when do you get time there \$\endgroup\$
    – wasif
    Mar 25 at 16:35
  • 1
    \$\begingroup\$ For school wifi, try using a VPN. \$\endgroup\$
    – emanresu A
    Mar 26 at 3:37
3
\$\begingroup\$

Pyth, 17 bytes

.v+PtXQ"da""th"\E

Test suite

Uses pretty much the same approach as ChartZ Belatedly's Jelly answer.


As an aside, this answer could shed 3/4 bytes if Pyth had an 'evaluate with argument' builtin, and an additional 1/2 if it had Jelly's 'transliterate' (Pyth builtins can be one or two bytes). This would put it at 11/12/13 bytes, which at best ties the 11 bytes Jelly takes. This is especially impressive since Jelly has to reverse the accessor, while Pyth doesn't (Pyth uses reverse Polish notation).

\$\endgroup\$
3
\$\begingroup\$

Jq, 69 bytes

Takes an object with keys "c" for the accessor and "l" for the list.

reduce((.c/"")[1:-1]|reverse[])as$c(.l;if$c=="d"then.[1:]else.[0]end)

Explanation

reduce        $0               as$c($1;             $2              )
  # the accumulator starts at $1. For each $0 (stored as the variable $c),
  # it becomes the result of $2 applied to it.
      ((.c/"")[1:-1]|reverse[])
  # the command (.c), split (/""), with the ends snapped ([1:-1])
  # reversed (reverse), every value inside this array  ([])
                                    .l;if$c=="d"then.[1:]else.[0]end
  # starting with the list (.l), if the character is "d" then the list
  # becomes its tail (.[1:]), otherwise its head (.[0]).

Jq play it!

Run test cases

\$\endgroup\$
6
  • \$\begingroup\$ You might want to make the explanation a separate block. \$\endgroup\$
    – user
    Mar 25 at 20:07
  • \$\begingroup\$ @OriginalOriginalOriginalVI Eh, I kind of liked how it was, plus it probably took shorter to load. \$\endgroup\$
    – Wezl
    Mar 25 at 20:11
  • 3
    \$\begingroup\$ Hehe funny byte number. Nice. \$\endgroup\$
    – lyxal
    Mar 25 at 21:39
  • \$\begingroup\$ it probably took like 1ms shorter to load so wouldn't have been noticeable \$\endgroup\$
    – ASCII-only
    Mar 27 at 8:47
  • 1
    \$\begingroup\$ $c=="d" -> $c>"a" \$\endgroup\$
    – ASCII-only
    Mar 27 at 8:51
3
\$\begingroup\$

Japt -h, 20 bytes

VÔkric)¬£=X¥'a?UÎ:UÅ

Try it

  • saved 2 thanks to @Shaggy
    1st input U = data
    2nd input V = command
    
    VÔk"cr" - reverse and remove 'cr'
    £ ... Ã - pass each remaining letters to :
    =         - reassign 1st input(U)
    X¥'a?UÎ   - 1st item if 'a'
    :UÅÃ      - else the rest
    -h flag to output result 
\$\endgroup\$
1
2
\$\begingroup\$

Stax, 10 bytes

Ç≈≡ø*fáì☺○

Run and debug it

Returns a string of codepoints if array, and number if it's a number. The code can be verified here: Try it

Explanation

"ahdD"|trDl
"ahdD"|t    translate 'a' to 'h' and 'd'  to 'D'
        r   reverse
         D  delete first element
          l eval

checking code:
cc|4{|u}a?
cc         dup twice
  |4     ? if it's an array:
    {|u}   convert to JSON
        a  otherwise leave as is
\$\endgroup\$
2
  • \$\begingroup\$ What does the | before the t do? EDIT: Oh, looks like it forms a "ligature" with t to make a new command. \$\endgroup\$
    – Wezl
    Mar 25 at 15:56
  • \$\begingroup\$ yep | is a prefix for a lot of commands \$\endgroup\$
    – Razetime
    Mar 25 at 16:02
2
\$\begingroup\$

Charcoal, 20 bytes

F⮌η≡ιa≔§θ⁰θd≔ΦθλθcIθ

Try it online! Link is to verbose version of code. Outputs using Charcoal's default format, which is each array element on its own line and each subarray double-spaced from the next (+1 byte to output in Python str format). Explanation:

F⮌η≡ι

Loop over the command characters in reverse order and switch on them.

a≔§θ⁰θ

For a replace the input with its first element.

d≔Φθλθ

For d filter the first element from the input.

cIθ

For c print the result.

\$\endgroup\$
2
\$\begingroup\$

Retina 0.8.2, 73 bytes

+`(a|(d))r.(((\[)|(?<-5>])|\d|(?(5),))+),?(?(2)(?<3>.*)|.*)
r$#2$*[$3
cr

Try it online! Link includes test cases. Explanation:

+`

Repeat until a match cannot be made.

(a|(d))r.(((\[)|(?<-5>])|\d|(?(5),))+),?(?(2)(?<3>.*)|.*)

Match either an a or d (remembering which), then an implied [, then a sequence of [s, ]s, ,s and digits, except no more ]s than [s and only matching ,s between [s and ]s, then an optional ,, then if it was a d that matched then replace the match of the first term with the tail of the list otherwise just delete the tail.

r$#2$*[$3

Keep the r, re-insert the [ if the d was matched, and insert the first term or tail as matched above.

cr

Finally delete the remaining cr.

\$\endgroup\$
2
\$\begingroup\$

Lua, 100 bytes

load[[t,c=...c:reverse():gsub('[ad]',load"if...=='a'then t=t[1]else table.remove(t,1)end")return t]]

Try it online!

Function that accepts a nested table structure and a string. I sure would be impressed to see this golfed further. Please note that original table structure will be modified when using d command, so don't pass it there if it have value to you (or, better yet, never use this code outside of TIO sandbox).

TIO link also includes a test suite.

\$\endgroup\$
2
\$\begingroup\$

Common Lisp, 106 104 bytes

(lambda(a c)(reduce(lambda(a c)(if(eq c #\a)(car a)(if(eq c #\d)(cdr a)a)))(reverse c):initial-value a))

Try it online!

Direct port of the racket answer.

\$\endgroup\$
2
\$\begingroup\$

Vyxal, 17 bytes

£ḢṪṘƛ\a=[&h|&Ḣ];¥

Try it Online!

A mess :P

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

Python 3, 80 79 75 bytes

f=lambda s,x:eval(['%s[1:]','%s[0]','x#%s','%s'][ord(s[0])%4]%'f(s[1:],x)')

Try it online!

By sheer luck, ord(s[0])%4 is able to distinguish between a, c, d, r.

\$\endgroup\$

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.