Summing? That's my forte!
Perl 5, 92 bytes
90 bytes of code + -pl
flags.
sub f{($b=$h{$a=pop}//$a)!=$a?f($b):$a}s%(\d+)\+(\d+)%f($1)+f$2%e&&redo;/=/;$_=$h{f$`}=f$'
Try it online!
I use the hashtable %h
to store the mapping between numbers.
The function (sub
) f
returns the number to which its input map (or its input if it's mapped to no number): $h{$a=pop}
retrieves the number toward which the input maps. If it's none, thanks to //$a
, the value of ($b=$h{$a=pop}//$a)
is the input ($a
). We make sure that this values isn't the input itself to not loop infinitely (!=$a
). Then, we either recursively call f
or return the input.
The main program consists of two steps:
- s%(\d+)\+(\d+)%f($1)+f$2%e&&redo
evaluates the first addition on the right side, while there is still an addition: it replaces x+y
by the result of the evaluation of f(x)+f(y)
.
- /=/;$_=$h{f$`}=f$'
does the assignment: /=/
allows to access the left side with $`
and the right side with $'
, then $h{f$`}=f$'
does the assignment. And we also assign it to $_
that is implicitly printed after each line.
JavaScript (Node.js), 81 bytes
v=x=>(v[x]=v[x]||x,v[x]-x?v(v[x]):x)
f=x=>l=>v[v(x)]=l.reduce((p,x)=>v(v(x)+p),0)
Try it online!
Receives input by calling f with the value to assign to, then calling the
result of that with an array of values to add together. (i.e. f(5)([4])
)
Repeat for multiple lines.
v
is used as a function to compute the actual current value of a number, and also as an object to store the actual values. First v[x]=v[x]||x
ensures that v[x]
is defined. v[x]-x
performs a comparison to determine whether this is the actual number or not. If the number does not map to itself, v(v[x])
recursively tries again, otherwise return x
.
f
performs the calculation and assignment, curried to save one byte, where the second call returns the computed value.
Jelly, 28 bytes
®y$ÐL
ṪÇ+Ç¥/Ṅ;®⁸Ǥ;©
⁸©ḷƓÇ€¤
Try it online!
This is one of the few Jelly programs where it seems to be terser to take input from standard input. It's a full program (writing a function would have been shorter but is banned by PPCG rules, because it wouldn't run correctly the second time). The input format looks like this:
[[5,[4]],[6,[5]],[7,[1,2,5]],[7,[5,2,1]],[18,[5,6,7]],[5,[3]],[10,[6,4]]]
Explanation
Helper function 1Ŀ
(translate an integer to its value)
®y$ÐL
ÐL Repeatedly, until there are no further changes,
$ apply the following unary function to {the input}:
y replace values using the mapping table
® stored in the register.
{Then return the eventual result.}
Rather conveniently, this helper function will work correctly either on a single value, or a list of values, due to the way y
is defined. If more than one mapping is given for a single value, we take the first mapping from the table. The mapping table is stored in the register (which is basically just a variable; Jelly only has one variable).
Helper function 2Ŀ
(evaluate one LET instruction)
ṪÇ+Ç¥/Ṅ;®⁸Ǥ;©
Ṫ On the last element of {the input},
Ç Run 1Ŀ,
/ left fold it via
¥ the following binary function:
+ add {the two arguments}
Ç and run 1Ŀ on {the result},
Ṅ write {the result} (and a newline) to standard output,
;® append the value of the register,
; prepend
¤ the following value:
⁸ {the input, without its last element}
Ç with 1Ŀ run on it
© and store that value in the register {and return it}.
We don't really want a return value here; we're just running this for its side effects (updating the register and outputting the assigned value). Jelly functions always return a value, though, so we just let the mapping table get returned, as that's tersest.
Main program
⁸©ḷƓÇ€¤
© Initialize the mapping table
⁸ with the empty string (which is also the empty list)
ḷ then evaluate and discard
¤ the following value:
Ɠ a line from standard input, parsed into a data structure
Ç€ with each element transformed via 2Ŀ
{and leave the empty string to be printed implicitly}
Normally, ⁸
would give us the first command-line argument when run in this context, but there isn't one (we're taking input from standard input), so it runs in an alternative mode that gives us the null string. The need to initialise the register (from its default value of 0
, which crashes y
) means that we can't mention the user's input implicitly, meaning that it's as cheap to take it from standard input (Ɠ
) as it would be to take it from a command line argument (³
or ⁸
), and being able to access the alternative use of ⁸
means that the unusual (for Jelly) form of input is actually a byte shorter.
It's possible this is improvable. I still haven't figured out why the second line needs to say ⁸Ǥ;
rather than just ;@Ç
– the two should be equivalent, as far as I understand Jelly, given the lack of use of µ
/ð
/ø
– but the latter crashes for some reason. Likewise, there are various other ways to rearrange the program without losing bytes, so it's possible that I've missed a way to make things a bit shorter.
Incidentally, changing the ḷ
in the last line to ;
gives you an interesting look into the internal workings of the program, as it'll then output the "history of the register" that's implicitly output by the return values of 2Ḷ
.