22
\$\begingroup\$

Introduction

I have decided that this Christmas, as a "present" to a friend, I wish to purchase the things described in the classic song "The 12 Days of Christmas". The only problem is, I don't know how to calculate the total price!

Your Task

Given a list of prices (in order from first to last), calculate the total price of all the items if they were ordered as described by the song. Remember, each item is ordered once more than the one before it, and this repeats for as many days as there are items!

Example

The first few lines of the song:

On the 1st day of Christmas, my true love gave to me
A partridge in a pear tree

On the 2nd day of Christmas, my true love gave to me
Two turtle doves,
And a partridge in a pear tree.

On the 3rd day of Christmas, my true love gave to me
Three French hens,
Two turtle doves,
And a partridge in a pear tree.

\$\vdots\$

The song then continues, each day adding in a new present, with the number increasing each time (e.g. "4 calling birds", "5 gold rings", etc.). up to a total of 12 days.

Therefore, the total number of each item as the song continues for 12 days goes: 1 partridge on day 1, 2 partridges and 2 doves on day 2, 3 partridges, 4 doves, and 3 French hens on day 3, etc.

Rules and Scoring

Your program should take as input a list of prices (which can be of any length), and calculate the total price in the manner described above. Programs which give me the wrong answer for their inputs will be disqualified. Shortest size in bytes wins!

Examples

[20, 20, 20]: 200
[25, 10]: 70
[10, 25, 10, 75]: 550

Example price table

Feel free to use this table to test your program. The correct output should be 51765.02.

Item Price
A partridge in a pear tree 27.50
A turtle dove 25.00
One French hen 5.00
One calling bird 70.00
A gold ring 65.00
One goose a-laying 25.00
One swimming swan 500.00
A milkmaid hired for 1hr 4.25
One lady dancing 289.65
One lord leaping 318.26
One piper piping 100.83
One drummer drumming 100.13

Or, as a single list of prices:

[27.50, 25.00, 5.00, 70.00, 65.00, 25.00, 500.00, 4.25, 289.65, 318.26, 100.83, 100.13]
\$\endgroup\$
11
  • 3
    \$\begingroup\$ I suggest including the entire song (or at least enough that it's clear how it progresses) to address concerns such as @Arnauld's \$\endgroup\$ Commented Dec 2, 2021 at 17:31
  • 2
    \$\begingroup\$ The table says “A pair of turtle doves”, which implies that the price for one dove should be a half of that, but it doesn't seem to be the case. \$\endgroup\$
    – xigoi
    Commented Dec 2, 2021 at 17:49
  • 2
    \$\begingroup\$ I changed the title a bit to make it clearer what the question's about (since at first it seems to imply the goal is to print the song), feel free to change or rollback if you dislike it. \$\endgroup\$
    – rydwolf
    Commented Dec 2, 2021 at 18:31
  • 2
    \$\begingroup\$ Would it be acceptable to expect prices as whole numbers of cents/units rather than decimal dollars? \$\endgroup\$ Commented Dec 3, 2021 at 1:20
  • 3
    \$\begingroup\$ @GingerIndustries I guess what I was getting at is if the floating-point-ness is a core part of the question, for languages where using floating points is more expensive byte-wise. The example uses decimal values, but it isn't explicit in the input specs. \$\endgroup\$ Commented Dec 3, 2021 at 1:25

31 Answers 31

17
\$\begingroup\$

05AB1E, 4 3 bytes

Œ˜O

Try it online!

sublists, flatten, sum.

I actually found this approach as I was trying writing an APL solution which ended up being almost identical to my answer for even-sum-subarrays.

\$\endgroup\$
1
  • \$\begingroup\$ Ahh it took me a while to understand why this was working, but that is very clever! \$\endgroup\$
    – Adnan
    Commented Dec 2, 2021 at 21:59
12
\$\begingroup\$

Jelly, 5 4 bytes

JƤSḋ

Try it online!

-1 byte thanks to pxeger!

Ignores the strings as input, just takes a list of 12 prices

How it works

Basically, the number of each item is given as

Day  1:  1
Day  2:  1  2
Day  3:  1  2  3
Day  4:  1  2  3  4
...
Day 12:  1  2  3  4  5  6  7  8  9 10 11 12
Total : 12 22 30 36 40 42 42 40 36 30 22 12

Which is just the prefixes of the range [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], summed down the columns. We then multiply each price by the quantity and take the total

JƤSḋ - Main link. Takes a list of 12 prices P on the left
 Ƥ   - Over the prefixes of P:
J    -   Convert to a length range
  S  - Sums of the columns
   ḋ - Dot product with P

Jelly, 3 bytes

ẆFS

Try it online!

A port of ovs' answer - sublists, flatten, sum

\$\endgroup\$
2
  • \$\begingroup\$ Looks like you don't need the ¹? \$\endgroup\$
    – pxeger
    Commented Dec 2, 2021 at 17:41
  • 1
    \$\begingroup\$ @pxeger Very nice, I overlooked that the prefixes of the prices aren't actually used! \$\endgroup\$ Commented Dec 2, 2021 at 17:43
9
\$\begingroup\$

JavaScript (ES6), 35 bytes

Expects an array of prices.

a=>a.map(v=>t+=p+=v*++i,i=t=p=0)&&t

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ I neglected to make this clear in the rules (which I have done now), but the program should accept an arbitrary-length list of prices. \$\endgroup\$
    – Ginger
    Commented Dec 2, 2021 at 17:59
  • 2
    \$\begingroup\$ @GingerIndustries Now fixed. (And this is shorter anyway. My original formula was unnecessarily complicated.) \$\endgroup\$
    – Arnauld
    Commented Dec 2, 2021 at 18:11
8
\$\begingroup\$

Julia 1.0, 26 bytes

!x=sum(cumsum(x.*keys(x)))

Try it online!

\$\endgroup\$
8
\$\begingroup\$

Excel, 52 69 59 bytes

Saved 10 bytes thanks to MarcMush pointing out how Excel interprets empty cells when doing math.

=SUM(LET(n,COUNT(A:A)+1,s,SEQUENCE(n),IFNA(A:A*s*(n-s),0)))

Input is in the range A:A.

  • LET(n,COUNT(A:A)+1 defines n to be one more than the number of cells in the range A:A that are a number. Why we need it to be one more will be clear later.
  • LET(~,s,SEQUENCE(n) defines s to be a vertical array of numbers 1 to the value of n we just defined. This is a list of how many of each gift is given at a time. 1 partridge, 2 doves, 3 hens, etc. (Lots of birds...)
  • (n-s) is best explained with an example. If there are 12 entries, this is (13-[1-13]) which becomes ([12-0]) which is how many days each gift is given. IE, the first gift is given on all 12 days and the 13th gift is given on 0 days because the list isn't that long.
  • A:A*s*(n-s), then, is (Value of each gift) * (number of times that gift is given on each day) * (number of days a gift is given) which is, therefore, a list of the total value of each gift item over all the days.
  • IFNA(~,0) accounts for the fact that the calculation above fails when the cell is empty because a number times an empty string is an error for Excel. This turns those errors into zeros.
  • SUM(LET(~,IFNA(~))) sums up all the values.

The screenshot below shows the last three steps in columns C:E.

LastSteps

\$\endgroup\$
3
  • \$\begingroup\$ This is impressive, however the requirements state that the input may be of any size. \$\endgroup\$
    – Ginger
    Commented Dec 3, 2021 at 21:23
  • 2
    \$\begingroup\$ @GingerIndustries Corrected / updated to account for any size list, including an empty list. \$\endgroup\$ Commented Dec 3, 2021 at 21:34
  • \$\begingroup\$ 59 bytes: =SUM(LET(n,COUNT(A:A)+1,s,SEQUENCE(n),IFNA(s*(n-s)*A:A,0))) \$\endgroup\$
    – MarcMush
    Commented Dec 9, 2021 at 0:26
7
\$\begingroup\$

R, 33 bytes

Or R>=4.1, 26 bytes by replacing the word function with \.

function(p)(rev(n<-seq(p))*n)%*%p

Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ I think we can improve this to function(p)(p:1*1:p)%*%p — using operator precedence of : over * \$\endgroup\$
    – JDL
    Commented Dec 3, 2021 at 13:43
  • \$\begingroup\$ @JDL that would work if we would write (k:1*1:k)%*%p, with k being length of p - but it turned out longer (I had it as an intermediate step in my golfing). \$\endgroup\$
    – pajonk
    Commented Dec 3, 2021 at 13:58
  • \$\begingroup\$ I guess --- but you can use scan for input in that case; k=sum(1|p<-scan());(k:1*1:k)%*%p is cheaper than your solution (you might be able to use = instead of <- for p too; I haven't checked) \$\endgroup\$
    – JDL
    Commented Dec 3, 2021 at 14:01
  • \$\begingroup\$ @JDL, agreed, cheaper for R<4.1 and longer for R>=4.1 :) EDIT: you need to wrap scan assignment in parentheses, so it's the same byte-count Try it online!. \$\endgroup\$
    – pajonk
    Commented Dec 3, 2021 at 14:03
7
\$\begingroup\$

Pyth, 4 bytes

ss.:

Try it online!

15 bytes (ungolfed) to avoid floating point precision errors.

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

Ruby, 36 30 bytes

->g{r=w=0;g.sum{|x|r+=x*w+=1}}

Try it online!

\$\endgroup\$
6
\$\begingroup\$

Vyxal, 5 bytes

żḂ*Þ•

Try It Online!

Vyxal is able to do the times-reverse thing more efficiently than Jelly (because you need the $ for chaining in Jelly, and Vyxal has a bifurcate command), but unfortunately it does not have 1-byte dot product like Jelly does, so the byte save gets canceled out.

Unfortunately (for me), caird+pxeger have found a 4-byter. I mean, I could pretty trivially get one by cheating:

Vyxal s, 4 bytes

żḂ**

Try It Online!

but I'll try to figure something out.

Vyxal, 4 bytes

ÞSf∑

Try it Online!

4 bytes by porting the same solution (ovs's) that everyone else is. Thanks to lyxal for finding this.

Vyxal d, 2 bytes

ÞS

Try it Online!

Flag abuse for the win. Credit to Aaroneous Miller.

\$\endgroup\$
4
  • \$\begingroup\$ 4 bytes \$\endgroup\$
    – lyxal
    Commented Dec 4, 2021 at 0:10
  • \$\begingroup\$ 2 bytes flaggy \$\endgroup\$ Commented Dec 13, 2021 at 15:36
  • \$\begingroup\$ What do the flags do? \$\endgroup\$
    – Ginger
    Commented Dec 17, 2021 at 22:49
  • \$\begingroup\$ @GingerIndustries s sums the stack. d deep sums the stack. \$\endgroup\$
    – hyperneutrino
    Commented Dec 17, 2021 at 23:06
5
\$\begingroup\$

Jelly, 4 bytes

ḋƤJS

Try It Online!

-1 byte thanks to caird coinheringaahing

\$\endgroup\$
2
  • \$\begingroup\$ 4 bytes \$\endgroup\$ Commented Dec 2, 2021 at 19:09
  • \$\begingroup\$ @cairdcoinheringaahing I could've sworn I tried that when I was trying to get the $ out of ḋJ$ƤS... anyway, thanks \$\endgroup\$
    – hyperneutrino
    Commented Dec 2, 2021 at 20:20
5
\$\begingroup\$

C (gcc), 54 53 bytes

d;f(x,n)float*x;{for(*x*=d=n;--d;)*x+=~d*(d-n)*x[d];}

Try it online!

Saved a bytes thanks to ceilingcat!!!

Inputs the list of prices as a pointer to an array along with its length (because pointers in C carry no length info).
Returns the total cost in the first element of the array.

\$\endgroup\$
0
4
\$\begingroup\$

Husk, 3 bytes

ΣΣQ

Try it online!

Uninventive port of ovs's O5AB1E answer: upvote that one instead.

\$\endgroup\$
4
\$\begingroup\$

APL+WIN, 16 bytes

Prompts for prices.

+/(n×⌽n←⍳⍴v)×v←⎕

Try it online! Thanks to Dyalog Classic.

\$\endgroup\$
0
4
\$\begingroup\$

x86 32-bit machine code, 23 bytes

d9 ee 31 c0 dd 04 c2 40 50 0f af c1 50 da 0c 24 de c1 58 58 e2 ee c3

Following the fastcall calling convention, takes the length in ECX and the address of an array of double-precision floating-point numbers in EDX, and returns the result on the FPU register stack.

Try it online!

Assembly:

.text
.global dayscost
.intel_syntax noprefix
dayscost:
    fldz                         # Push 0 onto the FPU register stack, for a running total.
    xor eax, eax                 # EAX = 0, for the current day number.
repeat:
    fld QWORD PTR [edx+8*eax]    # Push the new item's price onto the FPU register stack.
    inc eax                      # Add 1 to EAX. It is now the 1-indexed day number.
    push eax                     # Push EAX onto the regular stack.
    imul eax, ecx                # Multiply EAX by the number of remaining days.
    push eax                     # Push the product onto the regular stack.
    fimul DWORD PTR [esp]        # Multiply the price by that product.
    faddp                        # Add the full product to the running total.
    pop eax                      # Pop the product from the regular stack.
    pop eax                      # Pop to restore the day number in EAX.
    loop repeat                  # Repeat, counting down the number of remaining days in ECX.
    ret                          # Return.
\$\endgroup\$
4
\$\begingroup\$

Perl 5 + -p, 15 bytes

Using the insight from @Arnauld's answer.

$\+=$x+=$_*$.}{

Try it online!


Perl 5 + -pa, 26 bytes

$\+=(@F-$-++)*$_*$-for@F}{

Try it online!

\$\endgroup\$
4
\$\begingroup\$

Python 3, 69 64 61 55 bytes

Takes a list of floats as input.

lambda l:sum(o*-~c*(len(l)-c)for c,o in enumerate(l))

Try it here!

\$\endgroup\$
5
  • 1
    \$\begingroup\$ The square brackets can be removed, and you can replace abs(c-(len(l)+1)) with (len(l)+1-c), for a total of -7 bytes \$\endgroup\$
    – AnttiP
    Commented Dec 2, 2021 at 19:06
  • 2
    \$\begingroup\$ You should also include the def f(l): as well, or golf it to lambda l:sum(float(o)*c*abs(c-len(l)-1)for c,o in enumerate(l,1)) \$\endgroup\$ Commented Dec 2, 2021 at 19:11
  • 1
    \$\begingroup\$ Also, you can use eval instead of float or just take the input as a list of floats \$\endgroup\$
    – AnttiP
    Commented Dec 2, 2021 at 19:14
  • 1
    \$\begingroup\$ lambda l:sum(float(o)*-~c*(len(l)-c)for c,o in enumerate(l)) saves a further 2 bytes. \$\endgroup\$
    – Neil
    Commented Dec 2, 2021 at 20:07
  • 1
    \$\begingroup\$ o*-~c*(len(l)-c) can be o*~c*(c-len(l)) \$\endgroup\$
    – pxeger
    Commented Dec 5, 2021 at 13:32
3
\$\begingroup\$

Fortran, 116 bytes

Try it Online.

real,allocatable::A(:),s;read*,n
allocate(A(n));read*,A
do i=1,n;do j=1,i;s=s+A(j)*j
enddo;enddo
print'(f0.2)',s
end

Another demo of our old friend, Fortran (emphasis on old). Elegance, simplicity and flexibility are not words that spring to mind. The requirement to allow n inputs forced me to write those chunky allocate statements.

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

Pari/GP, 27 bytes

a->Pol((x*Ser(a))'/y=1-x)%y

Try it online!

See the input as a polynomial \$A=\sum_{i=0}^{n-1}a_ix^i\$. The derivative of \$A\ x\$ is \$(A\ x)'=\sum_{i=0}^{n-1}(i+1)\ a_ix^i\$. So \$(A\ x)'/(1-x)=\sum_{i=0}^{n-1}(\sum_{j=0}^{i}(j+1)\ a_j)x^i+O(x^n)\$. Then we only need to take the first \$n\$ terms and evaluate it at \$x=1\$.

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

SimpleTemplate 0.84, 86 bytes

This full program expects a variable number of arguments passed to the render() method. Argument unpacking can be used for convenience. Each argument is 1 gift.

{@eachargv}{@inc__}{@set*__ __,argc}{@set*_ __,_}{@incby_ T}{@incby-1argc}{@/}{@echoT}

The result is displayed on standard output, by default.

This works the same way as @caird coinheringaahing answer in Jelly.
However, everything is done manually, to obtain the Total row on the table.


Ungolfed:

The code above looks like gibberish, so, bellow is an ungolfed version of it:

{@set total 0}

{@each argv as value key key}
    {@inc by 1 key}
    
    {@set* key key, argc}
    {@set* value key, value}
    
    {@inc by value total}
    {@inc by -1 argc}
{@/}

{@echo total}

Yeah ... It still looks like gibberish...


About the language:

There are a few important things to notice here:

  • Plenty of whitespace isn't mandatory.
    {@eachargv} and {@each argv} do the same.
  • The line {@set total 0} isn't golfed to {setT 0}: it was removed because the {@incby_ T} will define the variable T.
  • The line {@each argv as value key key} is golfed into {@eachargv}.
    By default, the {@each} loop uses the variable _ for the value and __ for the key, if none were provided.
    This allows skipping all the "fluff" after argv.
  • {@inc by 1 key} and {@inc__} increment the key (or __) variable by 1. Due to rubbish math support, this has to be done.
  • {@set*__ __,argc} and {@set* key key, argc} both multiply the key variable by argc.
    The variable argc contains the length of the argv variable.
    This will calculate the number of times that the current gift was gifted on all 12 days.
    This should be 1 * 12, 2 * 11, 3 * 10 ... ((key + 1) * argc).
  • {@set*_ __,_} and {@set* value key, value} will multiply the key variable by the value, and save it into the value variable.
  • {@incby_ T} and {@inc by value total} will increment the total by the value calculated before.
  • {@incby-1argc} and {@inc by -1 argc} will decrement the argc variable by 1.
    This variable, initially, has the length of the argv array.
    At the end, the value will be 0.
  • {@echoT} and {@echo total} will display the total.

Yeah ... Very confusing...


Running the code:

You can run the code on: http://sandbox.onlinephpfunctions.com/code/b775fddea1ae9c869962f893ac915c8087cb779a

Please pick a version between 5.6 and 7.4.13. Can't fix the 8.0.0 compatibility issue without invalidating this answer.

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

IBM/Lotus Notes Formula Language, 102 bytes

Z:=L:=@Elements(i);T:=0;C:=1;@For(X:=1;X<=L;X:=X+1;@Set("T";T+i[X]*Z*C);@Set("Z";Z-1);@Set("C";C+1));T

There is no online interpreter for Notes so here is a screenshot of the expected output:

enter image description here

After more years than I can remember working with Lotus Notes and several posts on here, this will probably be my last Formula Language post as our company has just decommissioned the last Notes application that I was responsible for and my designer client will most likely soon be removed.

The end of an era. RIP, LN.

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

TI-Basic, 9 bytes

sum(cumSum(AnscumSum(1 or Ans

Takes input in Ans. Output is stored in Ans and displayed. Does not work for empty lists as TI-Basic does not support them.

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

Zsh, 65 bytes

Try It Online.

A=($@)
for i ({1..$#})for j ({1..$i})((s+=A[j]*j))
printf %.2f $s

Had to use printf to fix the output - Zsh arithmetic gives a funky result of 51765.019999999982 otherwise

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

convey, 33 bytes

Dude, i love convey

v<-1
12"0<
{**+@}
1">>^
^"=12
^+1

Try it online!

The start of the process:

enter image description here

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

Charcoal, 13 bytes

IΣEθ×ι×⊕κ⁻Lθκ

Try it online! Link is to verbose version of code. Explanation: Port of my golf to @GingerIndustries' Python answer.

   θ            Input list
  E             Map over prices
     ι          Current price
    ×           Multiplied by
        κ       Current index
       ⊕        Incremented
      ×         Multiplied by
           θ    Input list
          L     Length
         ⁻      Minus
            κ   Current index
 Σ              Take the sum
I               Cast to string
                Implicitly print
\$\endgroup\$
1
\$\begingroup\$

Rust 137 Bytes

fn r(v: Vec<f64>)->f64{let mut c=0.;let k=v.len()as f64;let s=v.iter().map(|x|{c+=1.;x*c*(k-c+1.)}).collect::<Vec<f64>>();s.iter().sum()}

Try it out!

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

Python 3, 145 137 bytes

p=list(map(eval,input().split()))
n=len(p)
d=1
t=0
for x in range(12):
 t=t+p[d-1]*d*(12-(d-1))
 d+=1
print(t)

Try it online!

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

Python 2, 64 bytes

i=input()
t,c,l=0,1,len(i)
for x in i:t+=x*l*c;l-=1;c+=1
print t

Try it online!

Python 2 because it will directly take the list as input and saves 1 byte by not needing the brackets for print.

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

Scratch, 223 bytes

Try it online!
Alternatively, 23 blocks

when gf clicked
delete all of[S v
repeat until<(answer)=[F
add(answer)to[S v
ask[]and wait
end
set[I v]to[-1
set[T v]to[
repeat(length of[S v
change[I v]by(1
repeat((length of[S v])-(I
change[T v]by((I)*(item((I)+(1))of[S v

Explanation

when gf clicked         Initiates code
delete all of[S v        Clears the "Shopping" list
repeat until<(answer)=[F  Loops code until the user inputs "F"
add(answer)to[S v          Adds user's input to the "Shopping" list
ask[]and wait               Prompts the user to give input
end                           Marks the end of code to be looped
set[I v]to[-1                   Resets the Item being accounted for
set[T v]to[                       Resets the Total cost of the items
repeat(length of[S v                Loops code for each item on the list
change[I v]by(1                       Increments the Item to be checked
repeat((length of[S v])-(I              Loops code for each day the item is purchased
change[T v]by((I)*(item((I)+(1))of[S v    Adds (item cost * quantity) to the total
\$\endgroup\$
1
\$\begingroup\$

APOL, 63 bytes

v(1 s(i));v(2 []);f(⌬(¹) a(2 x(x(+(∈ 1) I(∋)) -(l(¹) ∈))));⊕(²)
\$\endgroup\$
1
\$\begingroup\$

Haskell, 69 bytes

f x=sum$map sum[(map$uncurry(*))$zip x[1..n]|n<-[1..genericLength x]]

Try it online!

\$\endgroup\$

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.