Bigquery javascript UDF with array - javascript

I'm trying to run below query in bigquery using standard SQL and javascript UDF. The query takes forever to run, thus I'm not even able to verify if the function is working or not. Can you please let me know if there is anything wrong with the query that makes it run forever? I tried to change the function call
from IRRCalc(Array<FLOAT64> [cash_flow], ARRAY<INT64> [date_delta]) as IRR to IRRCalc(array(select cash_flow from input),array(select date_delta from input)) as IRR and it resolved the issue. Though I don't understand what's wrong with IRRCalc(Array<FLOAT64> [cash_flow], ARRAY<INT64> [date_delta]) as IRR. Can someone please have a look and shed some light? Many thanks.
Here's the query:
CREATE TEMPORARY FUNCTION IRRCalc(cash_flow ARRAY<FLOAT64>, date_delta ARRAY<INT64>)
RETURNS FLOAT64
LANGUAGE js AS """
min = 0.0;
max = 1.0;
do {
guess = (min + max) / 2;
NPV = 0.0;
for (var j=0; j<cash_flow.length; j++){
NPV += cash_flow[j]/Math.pow((1+guess),date_delta[j]/365);
}
if (NPV > 0){
min = guess;
}
else {
max = guess;
}
} while (Math.abs(NPV) > 0.00000001);
return guess * 100;
""";
WITH Input AS
(
select
cash_flow_date,
date_diff(cash_flow_date, min(cash_flow_date) over (),day) as date_delta,
cash_flow as cash_flow
from cash_flow_table
)
SELECT
cash_flow,
date_delta,
IRRCalc(Array<FLOAT64> [cash_flow], ARRAY<INT64> [date_delta]) as IRR
FROM Input;
And here's the table containing the raw data:
Row cash_flow_date date_delta cash_flow
1 2017-09-08 0 -159951.78265102694
2 2017-09-08 0 -9.272567110204461
3 2017-09-08 0 -1000.0
4 2017-09-08 0 -159951.78265102694
5 2017-09-27 19 3552.8711640094157
6 2017-09-27 19 -544.122218768042
7 2018-03-28 201 -576.4290755116443
8 2018-03-28 201 3763.8202775817454
9 2018-04-02 206 437225.5536144294

Can someone please have a look and shed some light?
to see the difference - just run your SELECT w/o UDF
SELECT
cash_flow,
date_delta,
ARRAY<FLOAT64> [cash_flow],
ARRAY<INT64> [date_delta]
FROM Input
As you can see here - for each row you create array with just one element in it - so actually two arrays with one element in each - that element that respectively belong to same row
when you do ARRAY(SELECT cash_flow FROM input), ARRAY(SELECT date_delta FROM input) you actually create arrays which with respective elements from all rows
finally - when you pass ARRAY with just one element in it - it looks like your while (Math.abs(NPV) > 0.00000001) always true thus loop runs forever
Something along these lines I think
Note: above answers your exact question - but you still most likely have issue with logic - if so - ask new specific question

Related

How to generate random number and print shiny if equals

I am learning to code and I am currently stuck on JavaScript object methods. I am trying to write a code to print 'shiny' if the random number generates = 5. How can I achieve that? Also, is it printing undefined which I do not know where it is coming from. Thank you for reading.
const pokemonGoCommunityDay = {
wildEncounters: ['machop','roselia','swablu','gible','snivy','fletchling'],
currentEncounter() {
while (this.currentEncounter) {
this.currentEncounter = this.wildEncounters[Math.floor(Math.random() * 6)];
console.log(this.currentEncounter);
if (/* How to make it generate a certain number and if =5 log shiny*/ === 5){
console.log('Shiny!');
}break;
}
}
}
console.log(pokemonGoCommunityDay.currentEncounter());
You already had the necessary piece in your code :)
Here's how you can do it:
if (Math.floor(Math.random() * 6)==5){
console.log('Shiny!');
}

greater than less than fail

I am using a simple if/else to check if a value is greater than another value, and display an appropriate message.
Looks like this:
$.post('api/getHeaderBudgetvsTarget.php', {headercriteria:headercriteria}, function(data) {
let obj = JSON.parse(data);
let totalbudget = obj[0].budget; // set to 1600
let totaltarget = obj[0].target; // set to 300
if(totaltarget > totalbudget) {
console.log('greater');
} else if(totaltarget < totalbudget) {
console.log('lesser');
}
});
Looking at the above logic, it should be clear to see that the console should display "lesser", because totaltarget(300) is not greater than totalbudget(1600).
But it's not. For some reason, it's saying that totaltarget(300) is greater than totalbudget(1600) - and I cannot figure out why.
My PHP script, getHeaderBudgetvsTarget.php, is not doing anything special. Just a simple query that does some calculations, as follows:
<?php
$sql = "SELECT
( SELECT ROUND(SUM(budget)) FROM `budget` ) AS 'budget',
( SELECT ROUND(SUM(`average`)) FROM `main` ) AS 'target',
( SELECT ROUND(SUM(`totalcheck`)) FROM `main` ) - ( SELECT ROUND( SUM(`budget`) ) FROM `budget` ) AS `budgetvstotalcheck`";
?>
Nothing special.
I checked the database design. The only difference I could find was the budget column in the budget table is set to a decimal.
The average column in the main table is set to a mediumint.
I don't think either one of those settings really make a difference (let me know if otherwise).
I am completely perplexed as to why this is happening.
I did attempt the following:
if($.isNumeric(totalbudget)) {
console.log('true');
} else {
console.log('false');
}
I checked both variables, and both appear to be numeric.
Why is this particular greater/lesser than logic not working?
Refer to the docs:
$.isNumeric() returns true only if the argument is of type number, or if it's of type string and it can be coerced into finite numbers
So $.isNumeric("300") is still true. You should convert your variables into number before comparing them like:
if (+totaltarget > +totalbudget)...

sorting two associative arrays/stacks

I am implementing an algorithm I designed and am exploring different approaches
This isn't a homework problem but I am going to explain it like one: lets say a merchant has bought inventory of apples on different days, and also sold some on different days. I want the weighted average timestamp of their current purchases.
I am storing this data object as timestamp string in epoch time, and quantity of apples. My dataset actually has the purchases and the sells in separate data sets, like so:
//buys
var incomingArray = {
"1518744389": 10,
"1318744389": 30
};
//sells
var outgoingArray = {
"1518744480": 3,
"1418744389": 5,
"1408744389": 8
};
and I would like the outcome to show only the remainding incomingArray timestamp purchase pairs.
var incomingArrayRemaining = {
"1518744389": 7,
"1318744389": 17
};
Where you see there was one outgoing transaction for 3 apples at a later timestamp, therefore subtracting from 10. And there were 13 outgoing transactions before the buy of 10, but after the purchase of 30, so they only subtract from the 30.
Note, if more than 10 were transferred after 10, it would subtract from both 10 and 30. The number of apples can never be less than 0.
First, to accomplish my goals it seems that I need to know how many are actually still owned from the lot they were purchased in.
Instead of doing stack subtracting in the LIFO method, it seems like this has to be more like Tax Lot Accounting. Where the lots themselves have to be treated independently.
Therefore I would have to take the timestamp of the first index of the sell in the outgoing array and find the nearest older timestamp of the buy in the incoming array
Here is what I tried:
for (var ink in incomingArray) {
var inInt = parseInt(ink);
for (var outk in outgoingArray) {
if (inInt >= 0) {
var outInt = parseInt(outk);
if (outInt >= inInt) {
inInt = inInt - outInt;
if (intInt < 0) {
outInt = inInt * -1; //remainder
inInt = 0;
} //end if
} //end if
} //end if
} //end innter for
} //end outer for
It is incomplete and the nested for loop solution will already have poor computational time.
That function merely tries to sort the transactions so that only the remaining balance remains, by subtracting an outgoing from the nearest incoming balance, and carrying that remainder to the next incoming balance
I feel like a recursive solution would be better, or maybe something more elegant that I hadn't thought of (nested Object forEach accessor in javascript)
After I get them sorted then I need to actually do the weighted average method, which I have some ideas for already.
First sorting, then weighted average of the remaining quantities.
Anyway, I know the javascript community on StackOverflow is particularly harsh about asking for help but I'm at an impasse because not only do I want a solution, but a computationally efficient solution, so I will probably throw a bounty on it.
You could convert the objects into an array of timestamp-value pairs. Outgoing ones could be negative. Then you can easily sort them after the timestamp and accumulate how you like it:
const purchases = Object.entries(incomingArray).concat(Object.entries(outgoingArray).map(([ts, val]) => ([ts, -val])));
purchases.sort(([ts1, ts2]) => ts1 - ts2);
Now you could iterate over the timespan and store the delta in a new array when the value increases (a new ingoing):
const result = [];
let delta = 0, lastIngoing = purchases[0][0];
for(const [time, value] of purchases){
if(value > 0){
// Store the old
result.push([lastIngoing, delta]);
// Set up new
delta = 0;
lastIngoing = time;
} else {
delta += value;
}
}

Check for prime in a list using sieve of Eratosthenes

I have an array as an input and i want to print the prime numbers that exist in that list. I was able to do that using trial division method. But I am struck at a point while trying to do the same thing using sieve of Eratosthenes method.
I tried it with below code, but got confused on how to compare the end result array with my input array list and return only those values that matches the input list. ( Detailed answer would be helpful as am a beginner in javascript).
var arr=[4,7,10,12,13,19,22,37];
function checkPrime(arr)
{
var output=[],primes=[];
var x=arr.length;
for(i=2;i<=arr[x-1];i++)
primes[i]=1;
for(i=2;i<=arr[x-1];i++)
for(j=2;j<=Math.sqrt(arr[x-1]);j++)
primes[i*j]=0;
for(i=0;i<=arr[x-1];i++){
if(primes[i]==1){
output.push(i);
}
}
return output;
}
console.log(checkPrime(arr));
When creating your output list, you want to compare against the values in arr, not the indices, so you need to replace primes[i] with primes[arr[i]].
So this:
if (primes[i] == 1) {
output.push(i);
}
Becomes this:
if (primes[arr[i]] == 1) {
output.push(arr[i]);
}

Sorting JSON Object via JavaScript odd results

Alright Odd results, not so much as they are expected. However I'm not sure how to over come it, I am having one of those days where every logical thing is the equivalent of a massive brain fart for me. Anyway. Lets say for the sake of ease. My array is numeric only nothing else in there.. My array ranges from 1-50 so my results upon sorting it are similar to 1, 10, 11, 12, 13.... 2, 20, 21, 22, 23... etc. When I need it to go like 1,2,3,4,5,6,7,8,9,10,11,12...
My simple little canned function is..
function sortJSONresultsByWidgetID(a,b)
{
if(parseInt(a.wigetID) == parseInt(b.wigetID))
{
return 0;
}
return parseInt(a.wigetID) > parseInt(b.wigetID) ? 1 : -1;
}
for reference I parseInt due to the JSON the way my JSON handles when I post it back and forth from the DB, I store the actual JSON in the DB and when passing it to the PHP it wraps quotes around the number turning them from INT to string (or from what I notice that may be browser based).
So here I am stuck now cause I want these things listed in a particular order and my brain wont work today.
EDIT example of me sorting results:
dashboardJSON.widgets.sort(sortJSONresultsByWidgetID);
You need to parse the ints with a radix of 10 and use the === operator instead of ==. I think that should do it.
function sortJSONresultsByWidgetID(a,b)
{
var widgetAId = parseInt(a.wigetID, 10);
var widgetBId = parseInt(b.wigetID, 10);
if(widgetAId === widgetBId)
{
return 0;
}
return widgetAId > widgetBId ? 1 : -1;
}
UPDATE - Here's with Ellian's optimization:
function sortJSONresultsByWidgetID(a,b)
{
return parseInt(a.wigetID, 10) - parseInt(b.wigetID, 10);
}

Categories

Resources