5
\$\begingroup\$

Am I under Budget?

Every 2 weeks when I get my cheque, I allocate a certain amount to last me until my next cheque, and bank the rest. To figure out how much I can spend per day and still remain under/on budget, I just need to divide the allocated amount by the number of days it needs to last me.

On Day 1 if the budget period is 14 days and I start with $400, I can spend ($400 / 14 =) $28.57 a day.

If I go over budget on any days though, I have less to spend during the rest of the budget period.

Say I spend $50 on Day 1. I now have $350 starting Day 2, and can only spend ($350 / 13 =) $26.92 a day instead of $28.57 for the remainder of the period.

Problem

Write a program/function that when given a starting allocation and a list of daily expenditures, returns a list of how much I could spend on each day to stay on budget, and a symbol indicating whether or not I was over/under/on budget that day.

Example

Pretend for this example the budget period is only 5 days.

  • Period Allocation = $100
  • Daily Expenditures = [20, 20, 30, 0, 0]

This should return (output variations are allowed. See Output section):

["= 20", "= 20", "^ 20", "V 15", "V 30"]
  • On Day 1, I can spend (100 / 5 =) $20. I spent the entire daily budget, so I was on budget (=). The first entry of the result is "= 20" to show this.

  • On Day 2, I can spend (80 / 4 =) $20. Again, I spent the entire amount, so the second result entry is the same as the first.

  • On Day 3, I can again spend (60 / 3 =) $20, but I went over budget by spending $30! I was allowed to spend $20, but went over, so the third result entry is "^ 20"; "^" meaning "over-budget.

  • On Day 4, I can spend (30 / 2 =) $15. I spent nothing however, so I was under budget. The fourth result entry will be "V 15"; "V" meaning "under-budget".

  • On Day 5, I can spend (30 / 1 =) $30. I again spent nothing and was under budget, so the fifth and final result entry is "V 30".

Input

Input will be:

  • A number representing the total money allocated for the period.
  • A sequence representing how much was spent on each day during the period

The number of days in a period is = to the length of the daily expenditure list.

Input Rules:

  • Your program must handle decimal allocation amounts.
  • The allocation amount can be taken as a number or string. A dollar sign is allowed for string representations (but optional).
  • You can assume the budget period will be at least a day long (daily expenditure list will contain at least 1 entry).
  • You can assume I won't spend more money than I allocated.
  • A delimited string would also be a acceptable form of input

Output

Output will be a sequence of symbols and numbers showing how much I was allowed to spend on that day, and whether or not I went over.

Output can be returned or printed to the stdout.

Output Rules:

  • Any non-numeric symbols can be used to indicate on/under/over budget, as long as you chose a different symbol for on, under and over. If you don't use "="/"V"/"^", make sure to specify in your answer what symbols you're using.

  • The symbol can appear before or after the number

  • Output can be any form of sequence where it's clear what parts belong to what day. The examples here use a sequence of strings, but a sequence of pairs/lists would be fine as well.

  • Output must be accurate to at least 2 decimal places (but more is fine). It must be properly rounded using 4/5 rounding if only accurate to 2 places.

  • A long string instead of a sequence of strings is fine too, as long as there's some delimiter separating output for each day so it's readable.

Test Cases

10, [1, 2, 3, 4, 0]
["V 2", "V 2.25", "^ 2.33", "^ 2", "= 0"]

25, [20, 2, 3]
["^ 8.3", "V 2.5", "= 3"]

1000, [123, 456, 400]
["V 333", "^ 438.5", "V 421"]

500, [10, 200, 0, 0, 100, 50, 50]
["V 71.43", "^ 81.67", "V 58", "V 72.5", "^ 96.67", "V 70", "V 140"]

This is code golf, so the smallest number of bytes wins.

\$\endgroup\$
7
  • \$\begingroup\$ are you sure of the last case? my code fails for only that! \$\endgroup\$ Apr 3, 2017 at 17:11
  • \$\begingroup\$ @officialaimm I'll double check it. I was pretty caffeinated when I made the second and forth cases. \$\endgroup\$ Apr 3, 2017 at 17:16
  • 3
    \$\begingroup\$ It should be 71.43, 81.67,58,72.5,96.67,95,140 \$\endgroup\$ Apr 3, 2017 at 17:17
  • \$\begingroup\$ @fəˈnɛtɪk Your're right. Updating. \$\endgroup\$ Apr 3, 2017 at 17:22
  • \$\begingroup\$ Wow my spelling sucks today. \$\endgroup\$ Apr 3, 2017 at 17:29

6 Answers 6

4
\$\begingroup\$

Javascript, 67 66 bytes

a=>b=>b.map(c=>`v=^`[(c>(e=((a-=c)+c)/d--))-(c<e)+1]+e,d=b.length)

Explanation

This is an anonymous function that takes input through currying syntax (f(a)(b)). In this case, the fist number is the total budget, and b is an array of the money spent during the time period.

The function loops over b, but first sets d to the length of the array b. Then, for each element c in b, an inner function is executed (`v=^`[(c>(e=((a-=c)+c)/d--))-(c<e)+1]+e). This inner function calculates the budget for that day by dividing the amount left (a) by the number of days left (d). This results in 0 if the amount spent today is smaller than the budget, 1 if both are equal, and 2 otherwise. This is then used as index into a string with the correct symbols, and then the budget for this day is appended to that.

Afterwards, both the amount of money left and the number of days left are decreased; the former by c, the money spent on this day, and the latter by 1. It turned out that the shortest way to write this is to decrement a inside the division, and then add c to it, so the actual numerator is just a.

Usage

Uses currying syntax. There might be a really small error in the intermediate values, because of the way JavaScript deals with arithmetic.

Test it

Try all test cases here:

let f=
a=>b=>b.map(c=>`v=^`[(c>(e=((a-=c)+c)/d--))-(c<e)+1]+e,d=b.length)

let testcases = [[100, [20, 20, 30, 0, 0]], [10, [1, 2, 3, 4, 0]], [25, [20, 2, 3]], [1000, [123, 456, 400]], [500, [10, 200, 0, 0, 100, 50, 50]]];
for (let test of testcases) {
    console.log(`f(${test[0]})(${test[1].join(", ")}): ${f(test[0])(test[1])}`);
}

\$\endgroup\$
1
  • \$\begingroup\$ The output is fine. That was fast! \$\endgroup\$ Apr 3, 2017 at 16:14
3
\$\begingroup\$

Python 3, 112 97 82 bytes

def f(a,b):
 l=len(b)
 for i in b:e=a/l;print('=v^'[(e>i)-(e<i)]+str(e));a-=i;l-=1

Try it online!

  • saved 15 bytes!!!! thanks to Luke
  • saved 15 bytes: removed unwanted variable r
\$\endgroup\$
4
  • 1
    \$\begingroup\$ ('V'if(e>i)else'^'if(e<i)else'=') could be shortened to '^=v'[(e>i)-(e<i)], saving 15 bytes \$\endgroup\$
    – Luke
    Apr 3, 2017 at 17:18
  • 1
    \$\begingroup\$ Updated test cases. \$\endgroup\$ Apr 3, 2017 at 17:23
  • \$\begingroup\$ That saved me 15, thanks a lot @Luke \$\endgroup\$ Apr 3, 2017 at 17:30
  • 2
    \$\begingroup\$ I made a mistake in the order of the string: it should be =v^. \$\endgroup\$
    – Luke
    Apr 3, 2017 at 20:45
2
\$\begingroup\$

Röda, 65 bytes

f p,e{a=#e;e|{|b|x=p/a-b;[("=V^"/"")[x//x^2^0.5],p/a];p-=b;a--}_}

Try it online!

A simple imperative solution. Returns a letter and a number for each day. Uses x//x^2^0.5 to calculate the sign of x.

Functional programming version (76 bytes):

f p,e{seq#e,1<>e|[(p-sum(e[:#e-_]))/_1-_,_2]|[("=v^"/"")[_//_1^2^0.5],_1+_]}
\$\endgroup\$
1
\$\begingroup\$

Haskell, 75 bytes

m#l@(a:b)=((,)=<<("V=^"!!).fromEnum.compare a$m/sum[1|x<-l]):(m-a)#b
_#_=[]

Usage example: 25 # [20, 2, 3] -> [('^',8.333333333333334),('V',2.5),('=',3.0)]. Try it online!

How it works:

m#l@(a:b)=                   -- if the list of spendings has at least one
                             -- element a, the result is
 (,)                         -- a pair of two times
         m/sum[1|x<-l]       --  m / <length of the input list>
                                 (the library function 'length' is of type 'Int',
                                 so I can't use it with '/') 
    =<<                      --  but the first element is modified by
      ("V=^"!!).fromEnum.compare a
                             --  picking a char from the string "V=^"
                             --  depending on the result of comparing it to a
           :(m-a)#b          -- followed by a recursive call with all but the first
                             -- spending and m adjusted 


_#_=[]                       -- base case: if the list of spendings is empty, the
                             -- result is also the empty list 
\$\endgroup\$
0
1
\$\begingroup\$

Python 3, 77 bytes

def f(a,l):
 d=len(l)
 for i in l:e=a/d;d-=1;print('=v^'[(e>i)-(e<i)],e);a-=i

Try it online!

  • using '=v^'[(e>i)-(e<i)] save a chunk of bytes. Thanks to Luke.

  • Saved some bytes by assigning len(l) to a variable and then decrementing it instead od holding another variable.

\$\endgroup\$
4
  • \$\begingroup\$ You could make this into an anonymous function to save some bytes. \$\endgroup\$ Apr 4, 2017 at 3:13
  • \$\begingroup\$ Anonymous function in the sense, using lambda? \$\endgroup\$ Apr 4, 2017 at 3:16
  • \$\begingroup\$ Yes. The functions don't need to be named. You can assume they'll be called appropriately. \$\endgroup\$ Apr 4, 2017 at 3:17
  • \$\begingroup\$ I dont think I can use anonymous function here. Lambda is a single line expression and I couldnt assign variables there. If that is not what you mean, can you please suggest some examples. \$\endgroup\$ Apr 4, 2017 at 3:35
1
\$\begingroup\$

Java (OpenJDK 8), 140 bytes

class B{void f(float a,float[]l){int d=l.length;for(float i:l){float e=a/d;d--;a-=i;System.out.format("%s%f ",(e<i)?'v':(e>i)?'^':'=',e);}}}

Try it online!

Ungolfed!

class B {
 void f(float a, float[] l) {
  int d = l.length;
  for (float i: l) {
   float e = a / d;
   d--;
   a -= i;
   System.out.format("%s%f ", (e < i) ? 'v' : (e > i) ? '^' : '=', e);
  }
 }
}
\$\endgroup\$

Your Answer

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

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