How to calculate original loan amount without year terms? - ruby

https://www.moneysmart.gov.au/tools-and-resources/calculators-and-apps/savings-goals-calculator
I want to get result like above calculator when I select:
I want to save: 6000
I want to spend it: As soon as possible
Starting balance: 0
Interest rate : 10%
Regular savings: 1000 Monthly
But I am getting not correct result using this code:
loan = 6000.0
interest = 10.0
monthly_payment = 1000.0
i =0.0
record = []
count = 1
add_interst = 0.0
while( loan>=0)
i = interest/(100*12)*loan
loan=i+(loan)-(monthly_payment);
add_interst = add_interst + i
end
puts add_interst
I am getting 181.42163384701658 which should be 168. I don't know where I am wrong.

The code doesn't work because you are doing the opposite of what the link you reference is doing. What they are calculating is saving interest, what you are calculating is loan interest.
Basically, this is how you should define the variables.Also, as others have pointed out, it is good to use BigDecimal to calculate money:
require 'bigdecimal'
balance = 0.to_d
interest = 10.to_d/1200.to_d
regular_saving = 1000;
goal =6000;
i = 0;
added_interest = 0
So, to correct things, you have to start from the starting balance (i.e 0) and start incrementing. Something like this:
while balance < goal
balance += regular_saving;
i = balance * (interest);
balance +=i;
added_interest+=i;
end
Note also, that in the last year you don't need to pay the full saving amount. You only need to pay to reach the goal. For that, you need to add a conditional statement to check goal - balance < regular_saving. If this was the case, the interest should be calculated in terms of the balance that should be paid (slightly less than the goal).

Related

Sort shopping list based on previous shopping trips

I want to sort a shopping list based on the order items were checked off in previous shopping trips. For example I go to the store and shop Apples, Bananas and Eggs.
Next I go to the store I shop Avocados and Tomatos and Apples. For my next trip the application sorts Avocados, Tomatos and Apples all before Eggs f.e.
I found this post talking about topological sorting: How to sort a shopping list based on previous pick order?.
However I am not sure how this should work since in theory I could have cycles (A user could theoretically check off apples and then bananas and the next time bananas are checked off before apples).
Could you guide me on how to tackle this problem?
Kind regards
I assume:
Past item orderings should guide ordering the current order.
Any new items appear after any items ordered historically.
Orderings further back in time should have less impact than more recent orderings.
My idea is to assign weights to items seen in past orders based on:
Their position in a historic ordering.
How old that odering is.
The weightings might need adjusting, but, using data from that other question you link to, the Python code below does create orderings based on historic orderings:
from collections import defaultdict
shop = [['Toothpaste', 'Bread', 'Meat', 'Vegetables', 'Milk', 'Ice cream'], # last
['CDs', 'Bread', 'Fruit', 'Vegetables', 'Juice', 'Sugar', 'Chocolates'], # last-but-1
['Meat', 'Juice', 'Milk', 'Sugar']] # last-but-2
def weight_from_index(idx: int) -> float | int:
"Items to the left are of LOwer wt and will sort first."
return idx + 1
def historic_multiplier(idy: int) -> float:
"Older rows have larger multipliers and so are of lower overall weight."
return (idy + 1)**1
def shopping_weights(history: list[list[str]]) -> dict[str, int | float]:
"Weight for items from historic shops."
item2weight = defaultdict(float)
for y, hist in enumerate(history):
for x, item in enumerate(hist):
item2weight[item] += historic_multiplier(y) * weight_from_index(x)
return dict(item2weight)
def order_items(items: list[str], weights) -> list[str]:
wts = weights.copy()
new_items = set(items) - set(wts)
# New items last, but in given order otherwise
max_wt = max(wts.values())
for itm in new_items:
wts[itm] = max_wt + 1 + items.index(itm)
return sorted(items, key = lambda i: wts[i])
item_weights = shopping_weights(shop)
new_shop = ['Curry', 'Vegetables', 'Eggs', 'Milk', 'CDs', 'Meat']
new_order = order_items(new_shop, item_weights)
print(new_order)
# ['CDs', 'Meat', 'Vegetables', 'Milk', 'Curry', 'Eggs']
# Update the historic item orders
shop.insert(0, new_order)

How to manage the number of loops in while loop Pseudocode

I'm a beginner and wanna ask about While Loop Pseudocode for the number of loops if i want it to be entered by user and not specifying how many, should i write it like this? or i have to declare the SM first?
Thank you
BEGIN
Student = 0
WHILE Student < SM
Get Work Efficiency, Task Completion Effectiveness, Team Work, SM # SM is
the number of students’ marks to be entered
Sum = Work Efficiency + Task Completion Effectiveness + Team Work
Competency = (Sum / 50) * 100
If Competency >= 70%
grade = ‘A’
display = “Exceed Expectation!”
else if Competency >= 40% AND Competency < 70%
grade = ‘B’
display = “Meet Expectation”
else if Competency >= 0% AND Competency < 40%
grade = ‘C’
display = “Below Expectation”
else
display = “Invalid input”
End if
Student = Student + 1
END WHILE
END
As you say, SM is provided by user's input, thus you should mention it somewhere. There is a lot of various ways of writing pseudocode and they mostly depend from your needs, so you could e.g. write:
SM <- integer user input
[rest of your code]
or wrap it in a function (that way you show that returned value is dependent from SM's value:
function foo(SM):
[rest of your code]

Best way to get max value in LINQ?

I'm newbie to LINQ. I will like to get know what's the highest value for 'Date', which method is preferred?
var ma1x= spResult.Where(p =>p.InstrumentId== instrument).OrderByDescending(u => int.Parse(u.Date)).FirstOrDefault();
var max2= spResult.Where(p =>p.InstrumentId== instrument).Max(u => int.Parse(u.Date));
Max or OrderByDescending ?
Max is better for both the developer and the computer.
Max will be always better because Max is semantic and meaningful.
Enumerable.Max Method
Returns the maximum value in a sequence of values.
msdn
You want the max value? Use Max. You want to order? Use OrderBy. The next developer will thank you. To quote Martin Fowler:
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
If you really want to use OrderBy to do the role of Max at least, wrap the orderby and the first in a method with a meaningful name. Something like ... Max. Great, now you have a meaningful OrderBy.
Lets see how this custom Max will do.
Enumerable.Max should be O(n) in the worst case when OrderBy use a quicksort which is O(n^2). So, the custom max is worst than the standard one...
Enjoy the performance bonus and go for Enumerable.Max. It is better for both the developer and the computer.
Edit:
Check Marco's answer to see how they perform in practice. A race of horses is always a nice idea to know which one is the faster.
.Max() should be faster. First of all the semantics of the method are clearer and your colleagues will know what your call does.
I've compared both your options on the AdventureWorks2014 database, with the following calls in LinqPad:
var times = new List<long>();
for(var i = 0; i < 1000; i++) {
Stopwatch sw = Stopwatch.StartNew();
var max2= SalesOrderHeaders.Max(u => u.OrderDate);
long elapsed = sw.ElapsedMilliseconds;
times.Add(elapsed);
}
var averageElapsed = times.Sum (t => t) / times.Count();
averageElapsed.Dump(" ms");
Generated SQL:
SELECT MAX([t0].[OrderDate]) AS [value]
FROM [Sales].[SalesOrderHeader] AS [t0]
GO
Result:
5 ms
var times = new List<long>();
for(var i = 0; i < 1000; i++) {
Stopwatch sw = Stopwatch.StartNew();
var max1 = SalesOrderHeaders.OrderByDescending(u => u.OrderDate).FirstOrDefault();
long elapsed = sw.ElapsedMilliseconds;
times.Add(elapsed);
}
var averageElapsed = times.Sum (t => t) / times.Count();
averageElapsed.Dump(" ms");
Generated SQL:
SELECT TOP (1) [t0].[SalesOrderID], [t0].[RevisionNumber], [t0].[OrderDate], [t0].[DueDate], [t0].[ShipDate], [t0].[Status], [t0].[OnlineOrderFlag], [t0].[SalesOrderNumber], [t0].[PurchaseOrderNumber], [t0].[AccountNumber], [t0].[CustomerID], [t0].[SalesPersonID], [t0].[TerritoryID], [t0].[BillToAddressID], [t0].[ShipToAddressID], [t0].[ShipMethodID], [t0].[CreditCardID], [t0].[CreditCardApprovalCode], [t0].[CurrencyRateID], [t0].[SubTotal], [t0].[TaxAmt], [t0].[Freight], [t0].[TotalDue], [t0].[Comment], [t0].[rowguid] AS [Rowguid], [t0].[ModifiedDate]
FROM [Sales].[SalesOrderHeader] AS [t0]
ORDER BY [t0].[OrderDate] DESC
GO
Result:
28ms
Conclusion: Max() is more concise and faster!
Purely speculative, but I'd imagine max2. It is just looping through each item and checking if the value is higher than the last.
While max1 is checking which is higher and reordering. Even if it's just moving pointers around (rather than moving values), this is still more work.
The Max method is better than FirstOrDefault both of them send a result as true, but the performance of Max is good.
This code:
var ma1x= spResult.Where(p =>p.InstrumentId== instrument).OrderByDescending(u => int.Parse(u.Date)).FirstOrDefault();
First check you condition, then sort them order by your condition, after that will be select and have more action to find your result.

Regroup By in PigLatin

In PigLatin, I want to group by 2 times, so as to select lines with 2 different laws.
I'm having trouble explaining the problem, so here is an example. Let's say I want to grab the specifications of the persons who have the nearest age as mine ($my_age) and have lot of money.
Relation A is four columns, (name, address, zipcode, age, money)
B = GROUP A BY (address, zipcode); # group by the address
-- generate the address, the person's age ...
C = FOREACH B GENERATE group, MIN($my_age - age) AS min_age, FLATTEN(A);
D = FILTER C BY min_age == age
--Then group by as to select the richest, group by fails :
E = GROUP D BY group; or E = GROUP D BY (address, zipcode);
-- The end would work
D = FOREACH E GENERATE group, MAX(money) AS max_money, FLATTEN(A);
F = FILTER C BY max_money == money;
I've tried to filter at the same time the nearest and the richest, but it doesn't work, because you can have richest people who are oldest as mine.
An another more realistic example is :
You have demands file like : iddem, idopedem, datedem
You have operations file like : idope,labelope,dateope,idoftheday,infope
I want to return operations that matches demands like :
idopedem matches ideope.
The dateope must be the nearest with datedem.
If datedem - date_ope > 0, then I must select the operation with the max(idoftheday), else I must select the operation with the min(idoftheday).
Relation A is 5 columns (idope,labelope,dateope,idoftheday,infope)
Relation B is 3 columns (iddem, idopedem, datedem)
C = JOIN A BY idope, B BY idopedem;
D = FOREACH E GENERATE iddem, idope, datedem, dateope, ABS(datedem - dateope) AS datedelta, idoftheday, infope;
E = GROUP C BY iddem;
F = FOREACH D GENERATE group, MIN(C.datedelta) AS deltamin, FLATTEN(D);
G = FILTER F BY deltamin == datedelta;
--Then I must group by another time as to select the min or max idoftheday
H = GROUP G BY group; --Does not work when dump
H = GROUP G BY iddem; --Does not work when dump
I = FOREACH H GENERATE group, (datedem - dateope >= 0 ? max(idoftheday) as idofdaysel : min(idoftheday) as idofdaysel), FLATTEN(D);
J = FILTER F BY idofdaysel == idoftheday;
DUMP J;
Data in the 2nd example (note date are already in Unix format) :
You have demands file like :
1, 'ctr1', 1359460800000
2, 'ctr2', 1354363200000
You have operations file like :
idope,labelope,dateope,idoftheday,infope
'ctr0','toto',1359460800000,1,'blabla0'
'ctr0','tata',1359460800000,2,'blabla1'
'ctr1','toto',1359460800000,1,'blabla2'
'ctr1','tata',1359460800000,2,'blabla3'
'ctr2','toto',1359460800000,1,'blabla4'
'ctr2','tata',1359460800000,2,'blabla5'
'ctr3','toto',1359460800000,1,'blabla6'
'ctr3','tata',1359460800000,2,'blabla7'
Result must be like :
1, 'ctr1', 'tata',1359460800000,2,'blabla3'
2, 'ctr2', 'toto',1359460800000,1,'blabla4'
Sample input and output would help greatly, but from what you have posted it appears to me that the problem is not so much in writing the Pig script but in specifying what exactly it is you hope to accomplish. It's not clear to me why you're grouping at all. What is the purpose of grouping by address, for example?
Here's how I would solve your problem:
First, design an optimization function that will induce an ordering on your dataset that reflects your own prioritization of money vs. age. For example, to severely penalize large age differences but prefer more money with small ones, you could try:
scored = FOREACH A GENERATE *, money / POW(1+ABS($my_age-age)/10, 2) AS score;
ordered = ORDER scored BY score DESC;
top10 = LIMIT ordered 10;
That gives you the 10 best people according to your optimization function.
Then the only work is to design a function that matches your own judgments. For example, in the function I chose, a person with $100,000 who is your age would be preferred to someone with $350,000 who is 10 years older (or younger). But someone with $500,000 who is 20 years older or younger is preferred to someone your age with just $50,000. If either of those don't fit your intuition, then modify the formula. Likely a simple quadratic factor won't be sufficient. But with a little experimentation you can hit upon something that works for you.

Summarizing Bayesian rating formula

Based on this url i found Bayesian Rating, which explains the rating model very well, i wanted to summarize the formula to make it much easier for anyone implementing an SQL statement. Would this be correct if i summarized the formula like this?
avg_num_votes = Sum(votes)/Count(votes) * Count(votes)
avg_rating = sum(votes)/count(votes)
this_num_votes = count(votes)
this_rating = Positive_votes - Negative_votes
Gath
It would look more like this:
avg_num_votes = Count(votes)/Count(items with at least 1 vote)
avg_rating = Sum(votes)/Count(items with at least 1 vote)
this_num_votes = Count(votes for this item)
this_rating = Sum(votes for this item)/Count(votes for this item)
If you are using a simple +/- system, Sum(votes) = Count(positive votes) (ie. treat + as 1, - as 0)
See also: Bayesian average.
Should the avg_rating not be:
Sum(votes)/Count(votes)
Yves

Resources