I want to sort the array and to store the fetched values into a new array for print. I tried with push() but there is an error is occurring and shows that" Cannot read property 'push' of undefined".
`
this.dataService.userprofile().subscribe((data:any) => {
let profile:any[]=data.profiles;
for(let index=0;index<profile.length;index++) {
const element = profile[index];
const today: number = Date.now();
var b = Math.abs(today - Date.parse(element["dob"]));
element["dob"] = Math.floor(b / (1000 * 3600 * 24 * 365.25));
if (element["active"]=="N"){
this.row.push(element);
}}
this.rowData = this.row;//ag-grid row
console.log(this.rowData)
})
`
Instead of using for loop that it is hard to read and maintain you better use Array.prototype.reduce() and using the dot notation
Also notice that in TypeScript you should avoid using type any
Code:
this.dataService.userprofile().subscribe((data: any) => {
this.rowData = data.profiles.reduce((acc, element) => {
const b = Math.abs(today - Date.parse(element.dob));
element.dob = Math.floor(b / (1000 * 3600 * 24 * 365.25));
return element.active == 'N' ? [...acc, element] : acc;
}, []);
console.log(this.rowData)
});
Declare row variable before for loop.
this.dataService.userprofile().subscribe((data:any) => {
let profile:any[]=data.profiles;
let row = [];
for(let index=0;index<profile.length;index++) {
const element = profile[index];
const today: number = Date.now();
var b = Math.abs(today - Date.parse(element["dob"]));
element["dob"] = Math.floor(b / (1000 * 3600 * 24 * 365.25));
if (element["active"]=="N"){
row.push(element);
}}
this.rowData = row;//ag-grid row
console.log(this.rowData)
})
Related
I want to generate some data:
function createData(stock, purchase, percentdown) {
const dataarray=[]
for(let i = 1; i < 59; i++) {
const startdate = new Date()
const enddate = new Date(startdate.setMonth(startdate.getMonth(), 1))
const date = new Date(startdate.getTime() + Math.random() * (enddate.getTime() - startdate.getTime()))
const dateFormat = date.getMonth() + 1 + '/' + date.getDate() + '/' + date.getFullYear()
// not getting the right dates from the above
// If its the second element being created, other than initial I want to use the last generated stockprice
const stockprice = stock * Math.floor(Math.random() * 10);
const percent = Math.floor(Math.random() * 10)
const percentDiff = (stockprice*percent)/100
const purchaseprice = parseInt(stockprice) - percentDiff
const message = MessageFilter(purchaseprice, stock, percent)
dataarray.push(
{
id:i,
date:dateFormat,
stock_price:stockprice,
purchase_price:purchaseprice,
message:message
}
)
}
return dataarray
}
What I want to get as output:
//Using example dates and id's
[
{
id:1,
date:11/06/2022,
stock_price: 12000,
purchase_price: 11400,
message:message
},
{
id:2,
date:11/07/2022, //date increased by 1 day
stock_price: 12600, //price increased from last stock_price,id:1, by a random percentage
purchase_price: 11400, //calculated using this stock price
message:message
}
{
id:3,
date:11/07/2022, //date increased by 1 day
stock_price: 12300, //price increased/decreased from last stock_price,id:2, by a random percentage
purchase_price: 11400, //calculated using this stock price
message:message
}
]
How do I access the previous generated stockprice?
Edit:
Parameters which need to be passed to the function to get the desired output:
1- stock i.e. stockprice from a form denoted by stock in the function for 1st calculation, after which the created stockprice will be used.
2- date - not required to be passed in as it will be todays date.
3- percentdown - required for calculation of purchaseprice
4- Initial purchase price denoted by purchase for 1st element and subsequent calculation will be done by purchaseprice generated in fucntion.
Edit 2:
if (i === 1) {
const stockprice = stock * Math.floor(Math.random() * 10);
} else {
const { stock } = dataarray[dataarray.length - 1];
const stockprice = stock * Math.floor(Math.random() * 10);
}
It gives me a stockprice is not defined error.
To access the last element of an array just use arr[arr.length - 1]. In this case, it would be:
const { stock_price } = dataarray[dataarray.length - 1]
Note: {...} is for destructuring, in order to extract the property stock_price of the object returned by the above expression.
I'm having trouble getting a set of change events to work consistently: I have a table set up that checks to see whether either an input has been updated and then, depending on what input gets updated, the code submitted below either changes the margin or the price.
If I only change the price, I consistently calculate margin correctly, and if I only change the margin, I consistently calculate price correctly. If I change one and then the other, the second setAttribute doesn't work. (e.g. changing the price updates the margin, but, after that, changing margin, does not update price).
I'm new to JS, but I've tried debugging and can't seem to nail this down. Any help would be much appreciated.
see link for codepen: https://codepen.io/skeanerw/pen/mdBpppE
function calcBuySellMargin(bracket, rowID) {
const vendPriceID = document.getElementById(`VendPrice_${bracket}_${rowID}`);
const sellPriceID = document.getElementById(`ItemPrice_${bracket}_${rowID}`);
const marginID = document.getElementById(`Margin_${bracket}_${rowID}`);
const priceMeth = document.getElementById(`priceMeth_${rowID}`).innerText;
const vpUOM = document.getElementById(`vpUOM_${rowID}`).innerText;
//when we change the margin adjust the sell price.
marginID.addEventListener('change', () => {
let marginValue = (marginID.value) / 100
let vendPriceValue = (vpUOM === 'M') ? vendPriceID.value / 1000 : vendPriceID.value;
let sellPriceVal = (priceMeth === 'M') ? ((vendPriceValue / (1 - marginValue)) * 1000).toFixed(0) : (vendPriceValue / (1 - marginValue)).toFixed(3);
sellPriceID.setAttribute('value', parseFloat(sellPriceVal));
})
//when we change the buy price or the sell price, adjust the margin.
function setMargin() {
let vendPriceValue = (vpUOM === 'M') ? vendPriceID.value / 1000 : vendPriceID.value;
let sellPriceVal = (priceMeth === 'M') ? sellPriceID.value / 1000 : sellPriceID.value;
const marginValue = parseFloat( (sellPriceVal - vendPriceValue) / sellPriceVal * 100 )
marginID.setAttribute('value', parseFloat(marginValue).toFixed(0));
}
vendPriceID.addEventListener('change', () => {
setMargin()
})
sellPriceID.addEventListener('change', () => {
setMargin()
})
}
window.onload = (event) => {
document.querySelectorAll('.marginDisplay').forEach(element => {
const rowID = (element.id.replace(/Margin_\d_/, ''));
let bracket = (element.id.replace(/Margin_/,''))
bracket = (bracket.match(/^[0-9]/, ''))
calcBuySellMargin(bracket, rowID);
})
}
I was able to resolve by replacing the setAttribute methods:
marginID.addEventListener('change', () => {
let marginValue = (marginID.value) / 100
let vendPriceValue = (vpUOM === 'M') ? vendPriceID.value / 1000 : vendPriceID.value;
let sellPriceVal = (priceMeth === 'M') ? ((vendPriceValue / (1 - marginValue)) * 1000).toFixed(0) : (vendPriceValue / (1 - marginValue)).toFixed(3);
sellPriceID.value = sellPriceVal;
})
function setMargin() {
let vendPriceValue = (vpUOM === 'M') ? vendPriceID.value / 1000 : vendPriceID.value;
let sellPriceVal = (priceMeth === 'M') ? sellPriceID.value / 1000 : sellPriceID.value;
const marginValue = parseFloat( (sellPriceVal - vendPriceValue) / sellPriceVal * 100 )
marginID.value = marginValue
}
TLDR When running a batch of 3 step functions in parallel, what is the easiest way to measure the total amount of time spent on step 1, step 2, and step 3 across all parallel operations?
Details
Suppose that I have some code that hits a rest endpoint, processes the data, and then jams the result into a database.
async function workFunction(id) {
const url = buildUrl(id);
const post = await fetchData(url); // step 1
const output = await crunchData(post); // step 2
await writeData(url, output); // step 3
console.log('done with ', id);
}
I have "bunch" of ID's to process, so I run the processing in parallel.
const idList = [1,2,3,4,5,6];
const promises = idList.map(async (id) => {
await workFunction(id);
});
const result = Promise.all(promises)
.then(() => console.log('All work done'))
.catch(() => console.log('Something went wrong'));
This works, but suppose that I run into a bottleneck that is slowing things down. I want to investigate which part of the worker func is the main culprit, so I butcher my beautiful worker function with some manual code to time each step and add the result to an accumulator.
let totalFetchTime = 0;
let totalCrunchTime = 0;
let totalDatabaseWriteTime = 0;
async function workFunction(id) {
const url = buildUrl(id);
let startTime, endTime;
startTime = performance.now();
const post = await fetchData(url);
endTime = performance.now();
totalFetchTime += (endTime - startTime);
startTime = endTime;
const output = await crunchData(post);
endTime = performance.now();
totalCrunchTime += (endTime - startTime);
startTime = endTime;
await writeData(url, output);
endTime = performance.now();
totalDatabaseWriteTime += (endTime - startTime);
}
This works, but it is ugly as sin. Is there a cleaner way to accomplish the same thing? The performance measurement APIs look like they are geared for this sort of thing, but I'm not sure the best way to to accumulation across parallel workers.
Complete code snippet
const database = {};
const performance = window.performance;
// -----------------------------------------------------------------------
// Helper routines. Nothing interesting here
async function writeData(key, value) {
console.log(`writeDB called with ${key} = ${value}'`);
return new Promise((resolve, reject) => {
setTimeout(() => {
database[key] = value;
console.log(`committed DB write to database ${key}=${value}`);
resolve(key);
}, 500 + Math.random() * 500);
});
}
async function fetchData(url) {
console.log(`Fetching URl ${url}`);
try {
const response = await fetch(url);
const result = await response.json();
console.log(`Worker resolving url ${url}`);
return result;
} catch (e) {
console.log(`Worker REJECTING url ${url}`);
throw e;
}
}
async function crunchData(input) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const result = input.body.split(/(\s+)/).length;
resolve(result);
}, 50 + Math.random() * 50);
});
}
function buildUrl(id) {
return `https://jsonplaceholder.typicode.com/posts/${id}`;
}
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// Main processing code.
let totalFetchTime = 0;
let totalCrunchTime = 0;
let totalDatabaseWriteTime = 0;
async function workFunction(id) {
// TODO: make this function less ugly
const url = buildUrl(id);
let startTime, endTime;
startTime = performance.now();
const post = await fetchData(url);
endTime = performance.now();
totalFetchTime += (endTime - startTime);
startTime = endTime;
const output = await crunchData(post);
endTime = performance.now();
totalCrunchTime += (endTime - startTime);
startTime = endTime;
await writeData(url, output);
endTime = performance.now();
totalDatabaseWriteTime += (endTime - startTime);
}
const idList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const promises = idList.map(async(id) => {
await workFunction(id);
});
function logPerformanceStats() {
console.log(`Total fetch time : ${totalFetchTime.toFixed(1)} ms`);
console.log(`Total crunch time : ${totalCrunchTime.toFixed(1)} ms`);
console.log(`Total write time : ${totalDatabaseWriteTime.toFixed(1)} ms`);
}
// -----------------------------------------------------------------------
const result = Promise.all(promises)
.then(logPerformanceStats)
.catch((e) => console.log('Something went wrong : ', e));
You could use the following, which is basically turning the basic tests you already perform into a class that allows the creation of timers like objects + adding an extra function to get more readable times from a human point of view.
/**
* Description of Class PerfTimer
*
* this class allow to create objects
* that can be used through their methods to measure execution time
* in a more straightforward way
*/
class PerfTimer {
#startTime;
#endTime;
// CONSTRUCTOR
constructor() {
this.#startTime = performance.now();
this.#endTime = undefined;
}
// FUNCTIONS
/**
* ```
* PerfTimer.reset()
* ```
* - resets a PerfTimer object, by reaffecting the following values for its private properties:
* - `#startTime`: current time at function call (in ms)
* - `#endTime`: undefined
*/
reset = () => {
this.#startTime = performance.now();
this.#endTime = undefined;
}
/**
* ```
* PerfTimer.stop()
* ```
* - stops the actual PerfTimer object,
* by affecting the current time (in ms) to the private property `#endTime`
*
* _use `performance.now()`_
*/
stop = () => this.#endTime = performance.now();
/**
* ```
* PerfTimer.resume()
* ```
* - resume the actual PerfTimer object,
* by unsetting the value of the private property `#endTime`
* which may have been set with a previous `PerfTimer.stop()` call.
*
*/
resume = () => this.#endTime = undefined;
/**
* ```
* PerfTimer.elapsedTime(unit = 'auto', returnNumber = false)
* ```
* - returns the elapsed time since the PerfTimer object creation or it's last reset.
* - 1st argument allows to change the unit of the returned value.
* - 2nd argument allows to select the type of the returned value between `Number` or `String` \
* this will only work when `unit` value equals `"ms"` or `"s"`
*
* **-- Arguments :**
* #param {'auto' | 'ms' | 's'} unit a `string` that allows to specify the **unit** of the returned value \
* accepted options are :
* - `"auto"` **[default value]**
* - `"ms"`
* - `"s"`
* #param {boolean} returnNumber a `boolean` that allows to specify the **type** of the returned value between `string` or `number`, \
* note that it **only works** if `unit` value is different from `"auto"` otherwise it will always return a `string`
* - `true` returned value will be a `number`
* - `false` returned value will be a `string` **[default value]**
*
* **-- Return Value :**
* #returns {string | number} `string` or `number`
* - `string` : \
* when `unit == "auto"` or if `returnNumber == false`
*
* - `number`: \
* when `unit != "auto"` **and** `returnNumber == true`
*/
elapsedTime = (unit = 'auto', returnNumber = false) => {
let elapsedTime; // will receive the elapsed time in ms (!! not rounded !!)
if (this.#endTime == undefined) {
let endTime = performance.now();
elapsedTime = endTime - this.#startTime;
} else {
elapsedTime = this.#endTime - this.#startTime;
}
if (unit == 'ms') { // if unit is "ms" will return the exact value of execution time in ms
if (returnNumber == false)
return elapsedTime + ' ms';
else if (returnNumber == true)
return elapsedTime;
} else
if (unit == 's') {
if (returnNumber == false)
return ( Math.round(elapsedTime) / 1000 ) + ' s';
else if (true)
return ( Math.round(elapsedTime) / 1000 ); // returns the ms value (rounded) divided by 1000
} else
if (unit == 'auto') {
return sToDHMS( Math.round( Math.round(elapsedTime) / 1000 ) );
}
}
} // END OF PerfTimer
/**
* ```
* function sToDHMS(seconds) { ... }
* ```
* - return a string which represent the provided time in `seconds` in a more readable way, \
* goes up to **days** ranging from **seconds**.
* - returned format vary upon the `time` value, defined formats are :
* - `'X+ days, XXh XXm XXs'`
* - `'XXh XXm XXs'`
* - `'XXm XXs'`
* - `'XXs'`
*
* _**note :** there are no filling `0` so sometimes a `XX` may result in a `X`_
*
* **-- Argument :**
* #param {number} seconds `number` in seconds
*
* **-- Return Value :**
* #returns {string} `string` format will vary upon the provided `seconds` value
* - **_days_** (`seconds >= 86400`) : \
* returned string format is `'X+ days, XXh XXm XXs'`
* - **_hours_** (`seconds >= 3600`) : \
* returned string format is `'XXh XXm XXs'`
* - **_minutes_** (`seconds >= 60`) : \
* returned string format is `'XXm XXs'`
* - **_seconds_** (`seconds < 60`) : \
* returned string format is `'XXs'`
*/
function sToDHMS(seconds) {
if (seconds >= 86400) { // days detected
let d = Math.floor( seconds / 86400 ), // days
h = Math.floor( ( seconds % 86400 ) / 3600 ), // hours
m = Math.floor( (( seconds % 86400 ) % 3600 ) / 60 ), // minutes
s = (( seconds % 86400 ) % 3600 ) % 60; // seconds
if (d == 1)
return `${d} day, ${h}h ${m}m ${s}s`;
else
return `${d} days, ${h}h ${m}m ${s}s`;
} else
if (seconds >= 3600) { // hours detected
let h = Math.floor( seconds / 3600 ), // hours
m = Math.floor( ( seconds % 3600 ) / 60 ), // minutes
s = ( seconds % 3600 ) % 60; // seconds
return `${h}h ${m}m ${s}s`;
} else
if (seconds >= 60) { // minutes detected
let m = Math.floor( seconds / 60 ), // minutes
s = seconds % 60; // seconds
return `${m}m ${s}s`;
} else
if (seconds < 60) { // only seconds
return `${seconds}s`;
}
} //
How to use :
A call to the PerfTimer constructor will create an instance of the class which is an object that contains 2 private properties :
#startTime initialized with a call to performance.now()
#endTime initialized with undefined
it also includes the following functions:
PerfTimer.reset() :
A call to this method will reassign #startTime value with a new call to performance.now() and set back #endTime to undefined.
PerfTimer.stop() :
will assign #endTime value with a new call to performance.now()
PerfTimer.resume() :
will set back #endTime value to undefined
PerfTimer.elapsedTime(unit = 'auto', returnNumber = false) :
returns the elapsed time since the PerfTimer object creation or it's last reset.
1st argument allows to change the unit of the returned value. options are: 'auto' | 'ms' | 's' if set to 'auto' the sToDHMS() method will be called to transform the result
2nd argument allows to select the type of the returned value between Number or String
this will only work when unit value equals "ms" or "s"
Example of utilisation :
let perf = new PerfTimer(); // #startTime is defined from creation
const post = await fetchData(url);
totalFetchTime = perf.elapsedTime(); // default 'auto' && returnNumber = false
perf.reset(); // reset #startTime
const output = await crunchData(post);
totalCrunchTime = perf.elapsedTime('ms', true);
perf.reset();
await writeData(url, output);
totalDatabaseWriteTime = perf.elapsedTime('s', true);
So this is the code that I wrote :
var array = [image1, image2, image3, image4, image5];
array.forEach(function(obj, num, arr){
function SH(){var random = Math.ceil(Math.random() * array.length); setTimeout(array[random].style="opacity:1;transition:0.5;", 3600000 * random);
setTimeout( array[random].style="opacity:0; transition:0.5;", 3600000 * random + 1);};
SH();
setInterval(SH(), 3600000 * arr.length )
});
I want to make a random Image visible for an hour and than stop displaying it and make the next one visible. Im getting the "Cannot set property style of undefined" error. How do I fix it?
var random = Math.ceil(Math.random() * Array.length); returns undefined.
It's because Array is a keyword in JS. Rename it to array
Thanks for the comment. There are actually multiple problems in that code. I wanted to give you the next step how to fix it. There is also an incorrectly defined setTimeout callback and you should also use length - 1
If you'd like a fixed version, here you go:
var array = ["image1", "image2", "image3"];
array.forEach(function (obj, num, arr) {
function SH() {
var random = Math.ceil(Math.random() * array.length - 1);
setTimeout(() => {
array[random].style = "opacity:1;transition:0.5;";
}, 3600000 * random);
setTimeout(() => {
array[random].style = "opacity:0; transition:0.5;";
}, 3600000 * random + 1);
}
SH();
setInterval(SH(), 3600000 * array.length );
});
After comments:
var array = ["image1", "image2", "image3"];
function SH() {
var random = Math.ceil(Math.random() * array.length - 1);
array.forEach(function (obj, num, arr) {
// if any other index than randomised one
if (num !== random) {
array[random].style = "opacity:1;transition:0.5;";
} else {
array[num].style = "opacity:0; transition:0";
}
});
}
SH(); // start first
setInterval(() => SH(), 3600000); // set the interval
I want to compound interest on a weekly/fortnightly/monthly/annual basis.
I also want an option to have a deposit amount that can be added in.
I have already tried the standard formula of calculating the final amount accrued, as seen here:
(source: gstatic.com)
For example here is my method for calculating the interest compounding weekly:
function calculateWeekly(state: any) {
const { savings, deposit ,interest, timePeriodSelector, timePeriodLength } = state;
let numberOfYears = 0;
if (timePeriodSelector === "weekly") {
numberOfYears = timePeriodLength / weeksInAYear;
} else if (timePeriodSelector === "fortnightly") {
numberOfYears = (timePeriodLength / weeksInAYear) * 2;
} else if (timePeriodSelector === "monthly") {
numberOfYears = (timePeriodLength / weeksInAYear) * weeksInAMonth;
} else if (timePeriodSelector === "annually") {
numberOfYears = (timePeriodLength / weeksInAYear) * weeksInAYear;
}
const weeklyRate = interest / 100 / weeksInAYear;
const lengthOfCompunding = numberOfYears * weeksInAYear;
let startingFigure = parseInt(savings) + parseInt(deposit);
//total gets added on for every time cycle of week
let total =
(startingFigure * (Math.pow(1 + weeklyRate, lengthOfCompunding) - 1)) / weeklyRate;
return roundToTwoDP(total);
}
The issue with the above code is that the deposit gets added into the calculation every time the interest accrues. So a deposit of $10 weekly for 10 weeks will actually get added up to $100.
I attempted a method to accrue the interest using a loop for each week here:
// loops how many times to compound the interest
for(let i = numberOfYears - (1/weeksInAYear); i > 0; i-= (1/weeksInAYear)){
let interestGained = (total * (Math.pow((1 + weeklyRate), lengthOfCompunding))) - total;
total += interestGained + savings;
}
Thanks for any help!
This should do what you want:
const range = (min, max) => {
const size = 1 + max - min
return [...Array(size).keys()].map(n => n + min)
}
const weeksInAYear = 52
const addWeeklyInterest = interestRatePerWeek => (savings, _) => savings + savings * interestRatePerWeek
const calculateTotal = (savings, numberOfYears, interestRatePerWeek) => {
const numberOfWeeks = numberOfYears * weeksInAYear
return range(1, numberOfWeeks).reduce(addWeeklyInterest(interestRatePerWeek), savings)
}
console.log(calculateTotal(1000.00, 1, 0.02))
Output is 2800.328185448178. You might want to round that for display purposes, but also keep in mind that if accuracy is important, you can't use floating-point numbers.