Calculate rental Costs in excel-vba - vba

Hi I'm currently trying to setup a Calculator for Rental Cars.
You'll put in the car category, the rental days, whether or not you want to book the fuel-flat and how many kilometers you'll travel, whether or not you'll need winter tires, if you're traveling to a certain destination and how many people will be in the car.
My Data-Spreadsheet currently looks like this:
http://i.imgur.com/P2kz6ts.png
So, if you would for example wanted to rent a Ford Fiesta for 2 days with 2 people, winter tires and fuel-flat for 80km to destination 2.
The calculator should now pick the price for 1-3 days and multiply it by 2 for two days.
To that the cost for winter tires will be added which are 3€ per day. Then it'll add the cost for the fuel-flat for 50 - 150 km, since you'll be traveling 80km. Since you're travveling to destination 2, the rental company is willing to give a discount of 15€. Finally the calculated cost will be divided by 2, since 2 people will rent the car and split the costs evenly.
That Calculation should look like this:
((30*2+(3*2)+13,80)-15)/2)
So in the End the total Cost of 32,4€ shall be displayed in a msgbox.
Now, how do i code that if the rental days are between 1-3, excel should take the values of that specific collumn and use it to calculate the cost. Moreover, if you're renting the car more than a week then the price for 6-7 days shall be used and additional days be added according to the category.
Problem fixed, look at the Answer.

Here's the code that fixed the Problem:
If rentaldays > 30 Then
Application.Cells(3, 3).Value = "You're trying to rent a Car for more than 30 Days. Please use the longterm program."
price = 0
End If
If rentaldays = 30 Then
monat = (Application.WorksheetFunction.VLookup(car, Sheets("Data").Range("A:K"), 7, False))
End If
If rentaldays > 7 Then
zusatz = price + (((rentaldays - 7) * Application.WorksheetFunction.VLookup(car, Sheets("Data").Range("A:K"), 6, False)))
rentaldays = rentaldays - (rentaldays - 7)
End If
If rentaldays = 6 Or rentaldays = 7 Then
woche = (Application.WorksheetFunction.VLookup(car, Sheets("Data").Range("A:K"), 5, False))
End If
If rentaldays > 3 And rentaldays <= 5 Then
tage = price + (Application.WorksheetFunction.VLookup(car, Sheets("Data").Range("A:K"), 4, False) * rentaldays)
End If
If rentaldays >= 1 And rentaldays <= 3 Then
tage = price + (Application.WorksheetFunction.VLookup(car, Sheets("Data").Range("A:K"), 3, False) * rentaldays)
End If

You need to make this easier , not "smarter"
Just add more columns!
Then you have 3 simple rules (english code)
if days >= 30 then
price = Col K 'lookup for car
days = days - 30
end if
if days > 7 then
price = price + ((days - 7) * Col J) 'lookup for car
days = days - (days - 7)
end if
if days > 0 then
price = price + hlookup( days, C:I .....) 'lookup for car
end if

Related

Mean of consecutive days without selling

I am trying to calculate the mean of Interval without selling of a product.
I thought that a good way to get this is:
Count (Days without selling) / Count (Intervals of consecutive days without selling)
Units Sold
0 1
1 4
2 0
3 0
4 0
5 7
6 0
7 0
8 0
9 0
10 1
11 0
In this example I had:
8 days without selling
3 Intervals of consecutive days without selling
So, 8/3 = 2.7 should be my result.
Counting days with No units sold I am using this:
x['Units Sold'] == 0).sum()
However, I don't figured out a good approach to calculate 'Intervals of consecutive days without selling' in a efficient way (considering I will run on multiple products)
Another approach using nunique
s = df["Units Sold"].eq(0)
d = s.sum()
i = s[s].index.to_series().diff().ne(1).cumsum().nunique()
final = d/i # 2.6666666666666665
Using eq, cumsum and diff
First we use eq(0) and sum, to count the amount of days where nothing was sold.
Then we get the cumsum of these days and check wether or not there's a difference between the rows. If this difference is 0, that means there was an interval.
days = x['Units Sold'].eq(0).sum()
intervals = x['Units Sold'].eq(0).cumsum().diff().eq(0)
mask = x['Units Sold'].shift(-1).eq(0)
days / (intervals & mask).sum()
Output
2.6666666666666665
You already knew how to get sum of count of 0, so try this to find number of consective group of 0
s = df['Units Sold'].eq(0)
(s & ~s.shift(fill_value=False)).sum()
Out[567]: 3
You can use:
df.eq(0).sum()/((df.eq(0)&df.shift().ne(0)).sum())
Output:
Units Solds 2.666667
dtype: float64

Matricial distribution

I have a list of projects with hours to be consumed, distributed linearly through the months:
Hours Aug Sep Oct Nov Dec
100 20 20 20 20 20
200 40 40 40 40 40
300 60 60 60 60 60
600 120 120 120 120 120
Some projects will end in different months, so it shoudn't mark any hour in the next months (must be 0):
Hours Aug Sep Oct Nov Dec End
100 33.3 33.3 33.3 0 0 Oct
200 50 50 50 50 0 Nov
300 60 60 60 60 60 Dec
600 143.3 143.3 143.3 110 60
However, we have to keep the proportion of 20% of the sum (20% * 600 = 120. I've put 20% because we have 5 months, but it could be different percentages) on each month, so:
Hours Aug Sep Oct Nov Dec End
100 20 30 50 0 0 Oct
200 60 50 30 60 0 Nov
300 40 40 40 60 120 Dec
600 120 120 120 120 120
I have a Sudoku-like problem here, where I need to respect the proportion of the column and keep the sum of the line on each project. I've tried in many ways (VBA or functions) to make this distribution, but I've failed so far. I believe someone has crossed with this problem before, so is there a way of doing this distribution programatically? Is there a name for this kind of distribution?
See the image below. Once you have the marginal sums filled in, enter this formula into B2 and fill in the rest of the table (enter it as an array formula with ctrl+shift+enter):
=IF(MATCH($H2,$B$1:$F$1,0)<COLUMNS($B$1:B$1),0,($A2-SUM(C2:$G2))/(SUM(IF(MATCH($H$2:$H$4,$B$1:$F$1,0)<COLUMNS($B$1:B$1),0,$A$2:$A$4))-SUM(IF(MATCH($H$2:$H$4,$B$1:$F$1,0)<COLUMNS($B$1:B$1),0,C$2:$G$4)))*B$5)
The example given will not have a unique solution, so the aim with the above formula is to balance the hours by starting at the end and moving backwards in time while applying hours proportionally to how many hours are left on each project. For example, after resolving Dec, the project on row 2 still has 200 hours to allocate and the project on row 3 still has 180 hours to allocate. The formula will therefore apply 120 * 200 / (200 + 180) hours in Nov from the project on row 2 and 120 * 180 / (200 + 180) hours from the project in row 3.
This methodology assumes that all projects start at the same time. If this assumption doesn't hold, VBA would probably be the way to go. I would sort the months by the number of active projects, smallest to largest, then apply the same sort of calculation as here.
I'm not 100% sure I got your question right, but hopefully yes because it took me quite a lot of time. It actually looks deceptively easy, but is in fact quite tricky.
So let's presume we have this table:
Now if I got it right, we basically want to count, how many hours we
used up already, and now we want to distribute what we have left
depending on the unused (empty) months
So, for example, in Row 3 (100 hours) we don't want to distribute any hours, because we already used up all 100 out of 100 hours
In the next row (4), we want to distribute 115 hours (200-85) to the remaining 2 cells => which would leave us with 57.5 hours per month left on shift
and et cetera...
Under presumption, that's what you want the algorhytm to do:
Private Sub divide_time()
Dim tbl As ListObject: Set tbl = Sheets("Sheet1").ListObjects("Table1")
Dim hour_dist() As Integer
ReDim hour_dist(1 To 3)
' first we need to learn how many hours total we have available per project
For i = 1 To 3
With tbl.ListColumns(1)
hour_dist(i) = .Range(i + 1) ' we store each value into an array per project
End With
Next i
Dim current As Double
Dim sumof As Double
Dim hours_left As Double
Dim empty_counter As Integer
For i = 1 To 3
'we reset all of the counters per row
sumof = 0
empty_counter = 0
'looping through all the column values in the row
For j = 2 To 6
current = tbl.ListRows(1).Range(i, j)
sumof = sumof + current ' we get a sum of the current values in the row
If (current = 0) Then 'if there is an empty cell, we keep track of it _
(so we know into how many cells we can still divide the remaining time)
empty_counter = empty_counter + 1
End If
Next j
' so we get how many hours we have left for the project _
in comparison to how many months are free to distribute
hours_left = (hour_dist(i) - sumof)
'if we also want to store the info, _
'what month we ended on before we distribute the remaining hours
If (hours_left = 0) Then
Select Case empty_counter
Case 0
tbl.ListRows(1).Range(i, 7) = "Dec"
Case 1
tbl.ListRows(1).Range(i, 7) = "Nov"
Case 2
tbl.ListRows(1).Range(i, 7) = "Oct"
Case 3
tbl.ListRows(1).Range(i, 7) = "Sep"
Case 4
tbl.ListRows(1).Range(i, 7) = "Aug"
End Select
Else
tbl.ListRows(1).Range(i, 7) = "Dec"
End if
If (empty_counter <> 0) Then '( we dont want to be dividing by 0 )
For n = 6 To (6 - empty_counter + 1) Step -1
'for each month we divide what we have left _
depending on the % of the months available
tbl.ListRows(1).Range(i, n) = (hours_left / empty_counter)
Next n
End If
' and we loop it for each and every row
Next i
End Sub
The resulting table will look like this:
I guess you need to think "backwards".
First distribute hours among active projects in month n (December).
Deduct these hours from respective project and move to month n-1, etc.

Calculating Weekly Returns from Daily Time Series of Prices

I want to calculate weekly returns of a mutual fund from a time series of daily prices. My data looks like this:
A B C D E
DATE WEEK W.DAY MF.PRICE WEEKLY RETURN
02/01/12 1 1 2,7587
03/01/12 1 2 2,7667
04/01/12 1 3 2,7892
05/01/12 1 4 2,7666
06/01/12 1 5 2,7391 -0,007
09/01/12 2 1 2,7288
10/01/12 2 2 2,6707
11/01/12 2 3 2,7044
12/01/12 2 4 2,7183
13/01/12 2 5 2,7619 0,012
16/01/12 3 1 2,7470
17/01/12 3 2 2,7878
18/01/12 3 3 2,8156
19/01/12 3 4 2,8310
20/01/12 3 5 2,8760 0,047
The date is (dd/mm/yy) format and "," is decimal separator. This would be done by using this formula: (Price for last weekday - Price for first weekday)/(Price for first weekday). For example the return for the first week is (2,7391 - 2,7587)/2,7587 = -0,007 and for the second is (2,7619 - 2,7288)/2,7288 = 0,012.
The problem is that the list goes on for a year, and some weeks have less than five working days due to holidays or other reasons. So I can't simply copy and paste the formula above. I added the extra two columns for week number and week day using WEEKNUM and WEEKDAY functions, thought it might help. I want to automate this with a formula or using VBA and hoping to get a table like this:
WEEK RETURN
1 -0,007
2 0,012
3 0,047
.
.
.
As I said some weeks have less than five weekdays, some start with weekday 2 or end with weekday 3 etc. due to holidays or other reasons. So I'm thinking of a way to tell excel to "find the prices that correspond to the max and min weekday of each week and apply the formula (Price for last weekday - Price for first weekday)/(Price for first weekday)".
Sorry for the long post, I tried to be be as clear as possible, I would appreciate any help! (I have 5 separate worksheets for consecutive years, each with daily prices of 20 mutual funds)
To do it in one formula:
=(INDEX(D:D,AGGREGATE(15,6,ROW($D$2:$D$16)/(($C$2:$C$16=AGGREGATE(14,6,$C$2:$C$16/($B$2:$B$16=G2),1))*($B$2:$B$16=G2)),1))-INDEX(D:D,MATCH(G2,B:B,0)))/INDEX(D:D,MATCH(G2,B:B,0))
You may need to change all the , to ; per your local settings.
I would solve it using some lookup formulas to get the values for each week and then do a simple calculation for each week.
Resulting table:
H I J K L M
first last first val last val return
1 02.01.2012 06.01.2012 2,7587 2,7391 -0,007
2 09.01.2012 13.01.2012 2,7288 2,7619 0,012
3 16.01.2012 20.01.2012 2,747 2,876 0,047
Formula in column I:
=MINIFS($A:$A;$B:$B;$H2)
Fomula in column J:
=MAXIFS($A:$A;$B:$B;$H2)
Formula in column K:
=VLOOKUP($I2;$A:$D;4;FALSE)
Formula in column L:
=VLOOKUP($J2;$A:$D;4;FALSE)
Formula in column M:
=(L2-K2)/K2

BlackJack Project - Can't make aces change from 11 to 1's

I'm currently making a blackjack game for my project in school in Visual Basic.
In blackjack, when you have aces (value initially 11) their value turns to 1 when the total value of the cards is > 21. In code, this would just take away 10 for every ace
I'm stuck on this.
This is the code I have (that doesn't work):
Do While PlayerValue > 21 And counter <= noAcesPlayer
counter += 1
PlayerValue -= 10
Loop
In a senario, I have a: 2, 8, A, 8 (=29)
But since there is an Ace, and the total value is > 21, the value should have 10 subtracted from it (=19) - the above code does not do this.
Another scenario would be 10, 8, A, A (=40)
Again, the two Aces should turn into 1's, since the total value > 21, giving 20.
Any help would be greatly appreciated. :)
Here is an approach
Public Enum CardFace
None
Ace
Two
Three
Four
Five
Six
Seven
Eight
Nine
Ten
Jack
Queen
King
End Enum
This code should produce a value of twenty
Dim cards As New List(Of CardFace) From {CardFace.Ten, CardFace.Eight, CardFace.Ace, CardFace.Ace}
Dim total As Integer = 0
Dim numofAces As Integer = 0
For Each c As CardFace In cards
Debug.WriteLine(c.ToString)
If c = CardFace.Ace Then
numofAces += 1
Else
total += c
End If
Next
If numofAces > 0 Then
If total + 11 + (numofAces - 1) > 21 Then
total += numofAces
Else
total += 11 + (numofAces - 1)
End If
End If
Debug.WriteLine(total)
The correct way to build a blackjack hand is the following (in pseudo-code):
Variables: total = 0, soft-flag = false
For each card in hand:
Add card value to total. Faces are 10, aces are 1.
If the card you added was an ace, set soft-flag = true
If total < 12 and soft-flag:
Add 10 to total
Else:
set soft-flag = false
That's it. Only one loop over the cards, no extraneous variables, and you're left with the total value and a flag indicating if the total is soft.

Advice and feedback on dividing cash amounts into actual counts of various bills and coinage

So I need an idea of how to divide out an amount of money into actual counts of various bills and coinage. I know this is confusing, so let me give an example:
$16.32 - Sixteen dollars and thirty-two cents
One $10 bill
One $5 bill
One $1 bill
One Quarter ($0.25)
One Nickel ($0.05)
Two Pennies ($0.01)
So as you can see, we're just getting the number of bills and coinage that goes into a value, which will change according to user input.
Here's my current setup (Visual Basic):
If 100 Mod amount < 0 Then
If 50 Mod amount < 0 Then
' Continue this pattern until you get all the way down to the end ($0.01)
Else
While amount > 50
fiftiesAmount += 1
amount -= 50
End If
Else
While amount > 100
hundredsAmount += 1
amount -= 100
End If
Basically, each If statement determines whether or not your total amount needs an extra billing amount of that type, and then either adds to the amount of bills/coinage already created or moves on to the next amount.
Is this an efficient way of doing things, or am I missing out on an easier/faster algorithm/pattern that would make my life, and whoever is reading my code's life easier?
If you need extra details, I'll be happy to edit the question as needed.
Convert your amount to cents (it's easier). Divide by the currency value being tested, and then deduct that amount from the balance (pseudo-code)
Value = 16.32 * 100 ' Convert to cents
If Value > 10000 ' Hundreds
Hundreds = Value / 10000 ' How many?
Value = Value - (Hundreds * 10000) ' Reduce amount accordingly
End If
If Value > 5000 ' Fifties
Fifties = Value / 5000
Value = Value - (Fifties * 5000)
End If
If Value > 2000 ' Twenties
Twenties = Value / 2000
Value = Value - (Twenties * 2000)
End If
Repeat until you have less than 100, at which point you start with coins (50, 25, 10, 5)
Once you've got > 10, you've reached pennies; save them, reduce Value by that amount, and
Value is zero, so you're finished.