I am using NodeJS and Express and iterating over an array of strings, for example:
[ "1" , "+" , "B4", "*", "8"]
If the string contains a letter, the function should go off and call a GET method to retrieve a value from the Database. My code so far looks like this:
function processFormula(formula) {
console.log(formula)
var arr = formula.split(" ");
for (var i = 0; i < arr.length; i++) {
if (arr[i].match(/[a-z]/i)) {
/* fetch the value and store it in arr[i] */
}
return arr.toString();
}
My problem is that the method which goes off to fetch the value takes longer to execute than the processing thread, resulting in
undefined
cropping up a lot. I am struggling to understand where exactly I should be placing my callback to deal with this situation iteratively?
Any help is greatly appreciated!
That is tricky to coordinate. You could try using a HTTP request library like axios that uses promises. Then, you can use Promise.all to coordinate all the requests.
You can add another if inside the for and return until you at the last element:
for(var i = 0; i < arr.length; i++){
if (arr[i].match(/[a-z]/i)) {
/* fetch the value and store it in arr[i] */
}
if(i == arr.length-1){
return arr.toString();
}
}
And a suggestion, try using array.length outside for loops, because each loop you will be calculating the length of the array to check if condition is achieved, therefore going through array each time. (I didn't change that in my answer). Just do it before the loop and do var size = array.length
Related
I want to check that a range of cell are empty or has any values in them, I use this for loop :
for (let i = 0; i <= namesRange.getCellCount(); i++) {
if (namesRange.getCell(i,0).getText() == "")
{
break;
}
bookedCount += 1;
}
However this iteration is extremely slow (as is the use of Range.getValue, but the console warns you that iterating with .getValue is slow, does not warn you with getText) It takes several seconds to iterate over a very short list of 10 elements.
Is there any way to check for the values of a cell in a speedy manner using ExcelScripts?
Does this mean that, even if I develop a UDF or a ribbon Add-In with office.js and Node.js it will also be this extremely slow for iterating over cells?
Is there any way to make this faster?
The reason your code is likely performing slowly is that the calls to getCell() and getText() are expensive. Instead of performing these calls every time in the loop you can try a different approach. One approach is to get an array of the cell values and iterate over that. You can use your namesRange variable to get the array of values. And you can also use it to get the row count and the column count for the range. Using this information, you should be able to write nested for loops to iterate over the array. Here's an example of how you might do that:
function main(workbook: ExcelScript.Workbook) {
let namesRange: ExcelScript.Range = workbook.getActiveWorksheet().getRange("A1");
let rowCount: number = namesRange.getRowCount();
let colCount: number = namesRange.getColumnCount();
let vals: string[][] = namesRange.getValues() as string[][];
for (let i = 0; i < rowCount; i++) {
for (let j = 0; j < colCount; j++) {
if (vals[i][j] == "") {
//additional code here
}
}
}
}
Another alternative to the first answer is to use the forEach approach for every cell in the range of values.
It can cut down the amount of variables you need to achieve the desired result.
function main(workbook: ExcelScript.Workbook)
{
let worksheet = workbook.getActiveWorksheet();
let usedRange = worksheet.getUsedRange().getValues();
usedRange.forEach(row => {
row.forEach(cellValue => {
console.log(cellValue);
});
});
}
Basically i have to create a quiz with 3category. each with 5questions.
I would have to push the selected category-questions into this new array from the array with all the questions. I am unable to do so.
pushSelectedQuestion() {
for (var i = 0; i < this.getNumberOfQuestion; i++) {
if (usercategory == questionPool[i].category) {
mcqSelected.push(questionPool[i])
return mcqSelected;
}
}
}
usercategory = input from user.
if user chooses category 1.
if (1 == questionPool[1].category) (if it matches the category) then it will be pushed.
This is the part which i cant do
Well, from the information you've provided, there's one main issue here - the return statement is definitely shortcutting the loop - so even if you have everything else right, you'll only ever get the first matching question. The rest will have been cut out by the return statement, which stops the function and returns the value.
pushSelectedQuestion() {
for (var i = 0; i < this.getNumberOfQuestion; i++) {
if (usercategory == questionPool[i].category) {
mcqSelected.push(questionPool[i])
// the below line is causing this loop to end after the first time through the list.
// Remove it and then put a console.log(mcqSelected);
// here instead to see the value during each iteration of the loop.
return mcqSelected;
}
}
}
There are a lot of ways to accomplish what you want to do here though. For example, you could just use the javascript Array.filter method like so
let selectedQuestions = questionPool.filter(question => question.category == userCategory)
Maybe I am not understanding your question correctly, but can't you use nested arrays. If the questions are categorized beforehand that is.
How can I get the value BrandName in this image using javascript loop.
UPDATED: Since data variable you use to display the response is already a CartObject then use:
for (var i = 0, len = data.CartLists.length; i < len; i++) {
console.log( data.CartLists[i].Item.BrandName );
}
An alternative to the one VisioN said is the following:
for (var CartItemId in CartObject.CartLists) {
Console.log(CartObject.CartLists[CartItemId].Item.BrandName);
}
However, If you would attach an Prototype to the JSON object, you could obtain an Object in the for-loop instead of an Integer (Number).
for (var CartItem in CartObject.CarLists) {
Console.log(CartItem.Item.BrandName);
}
Note that if you are going to make everything right, you should insert the following in the for-loop:
if (CartObject.CarLists.hasOwnProperty(CartItem)) {
Console.log(CartItem.Item.BrandName);
}
This example will work, but as seen in the comments below. The use of it is not what it is designed for. The For-In loop is designed to loop over Object properties, not Array items.
See a screenshot of my returned data i did a console.log on which i need to do a for each on.
i have been trying things like this to no avail...?
for (var point in arrayLatLngPoints)
{
addMarkers(point.timestamp, point.lat, point.lng, point.timestamp, strUserName, pathColour);
}
Don't use for..in to loop an array, use normal for loop instead.
for (var i = 0; i < arrayLatLngPoints.length; i++)
{
var point = arrayLatLngPoints[i];
addMarkers(point.timestamp, point.lat, point.lng, point.timestamp, strUserName, pathColour);
}
I have a JSON response like this:
var errorLog = "[[\"comp\",\"Please add company name!\"],
[\"zip\",\"Please add zip code!\"],
...
Which I'm deserializing like this:
var log = jQuery.parseJSON(errorLog);
Now I can access elements like this:
log[1][1] > "Please add company name"
Question:
If I have the first value comp, is there a way to directly get the 2nd value by doing:
log[comp][1]
without looping through the whole array.
Thanks for help!
No. Unless the 'value' of the first array (maybe I should say, the first dimension, or the first row), is also it's key. That is, unless it is something like this:
log = {
'comp': 'Please add a company name'
.
.
.
}
Now, log['comp'] or log.comp is legal.
There are two was to do this, but neither avoids a loop. The first is to loop through the array each time you access the items:
var val = '';
for (var i = 0; i < errorLog.length; i++) {
if (errorLog[i][0] === "comp") {
val = errorLog[i][1];
break;
}
}
The other would be to work your array into an object and access it with object notation.
var errors = {};
for (var i = 0; i < errorLog.length; i++) {
errors[errorLog[i][0]] = errorLog[i][1];
}
You could then access the relevant value with errors.comp.
If you're only looking once, the first option is probably better. If you may look more than once, it's probably best to use the second system since (a) you only need to do the loop once, which is more efficient, (b) you don't repeat yourself with the looping code, (c) it's immediately obvious what you're trying to do.
No matter what you are going to loop through the array somehow even it is obscured for you a bit by tools like jQuery.
You could create an object from the array as has been suggested like this:
var objLookup = function(arr, search) {
var o = {}, i, l, first, second;
for (i=0, l=arr.length; i<l; i++) {
first = arr[i][0]; // These variables are for convenience and readability.
second = arr[i][1]; // The function could be rewritten without them.
o[first] = second;
}
return o[search];
}
But the faster solution would be to just loop through the array and return the value as soon as it is found:
var indexLookup = function(arr, search){
var index = -1, i, l;
for (i = 0, l = arr.length; i<l; i++) {
if (arr[i][0] === search) return arr[i][1];
}
return undefined;
}
You could then just use these functions like this in your code so that you don't have to have the looping in the middle of all your code:
var log = [
["comp","Please add company name!"],
["zip","Please add zip code!"]
];
objLookup(log, "zip"); // Please add zip code!
indexLookup(log, "comp"); // Please add company name!
Here is a jsfiddle that shows these in use.
Have you looked at jQuery's grep or inArray method?
See this discussion
Are there any jquery features to query multi-dimensional arrays in a similar fashion to the DOM?