Recurrent inline versus function within function? - javascript

I have a situation where I'm writing multiple functions that share a method of work and would really like to refactor and tidy up this code, rather than having these same blocks occur countless times only to execute slight differences. Given a block of information, I scan through each entry and perform operations on the block in question. An example of the recurrent function is as follows:
function basicFunc() {
var totalX = 2000, totalY = 2000;
for (var y = 0; y < totalY; y++) {
for (var x = 0; x < totalX; x++) {
/* Fake operation for theory */
var fakeVar = (y * x);
}
}
};
Comparative to:
function eachBlock(whatToDo, totalX, totalY) {
for (var y = 0; y < totalY; y++) {
for (var x = 0; x < totalX; x++) {
/* Fake operation for theory */
return whatToDo;
}
}
};
function basicFunc() {
var totalX = 2000, totalY = 2000;
eachoBlock("var fakeVar = (y * x)", totalX, totalY);
};
This works fine for single lines to be passed as the whatToDo parameter. How would you go about passing multiple lines to eachBlock(), say if you have a bunch of operations to do instead of the one var FakeVar operation?
TLDR: How can you use a function call within a function to wrap the original block of code operations it performed before becoming a separate function?

return whatToDo; in your “faster” example causes both loops to be skipped immediately and the function to exit. They don’t have the same effect, so your benchmark doesn’t apply.
How to do it, anyways: pass a function, call the function. There’s not a huge distinction in JavaScript, which is one of its most useful features.
function eachBlock(whatToDo, totalX, totalY) {
for (var y = 0; y < totalY; y++) {
for (var x = 0; x < totalX; x++) {
/* Fake operation for theory */
whatToDo(y, x);
}
}
}
function basicFunc() {
var totalX = 2000, totalY = 2000;
eachoBlock(function(y, x) {
var fakeVar = (y * x);
…
}, totalX, totalY);
}

Related

How to create custom double for loop in JS

So at the moment I'm trying to create a javascript application that uses quite a few nested for loops eg.
for (var i = 0; i < a; i++) {
for (var j = 0; j < b; j++) {
//Code to run
}
}
So for the sake of neatness I thought I could make some sort of function for this purpose that could be called upon like this
doubleLoop(conditionA, conditionB) {
//Code to execute
}
Is this at all possible in Javascript or am I just gonna have to make do with loads of double for loops?
I suppose you could do something like make conditionA and conditionB functions or something, but a simpler alternative would be to just split your functionality up into functions.
Something like this:
function draw(){
doOuterTask();
}
function doOuterTask(){
for (var i = 0; i < a; i++) {
doInnerTask();
}
}
function doInnerTask(){
for (var j = 0; j < b; j++) {
//Code to run
}
}
Here's a more specific example:
function setup() {
createCanvas(400, 400);
}
function draw() {
background(0);
drawGrid(10, 10);
}
function drawGrid(rowCount, columnCount){
for(var rowIndex = 0; rowIndex < rowCount; rowIndex++){
drawRow(rowIndex, rowCount, columnCount);
}
}
function drawRow(rowIndex, rowCount, columnCount){
for(var colIndex = 0; colIndex < columnCount; colIndex++){
var circleWidth = width/columnCount;
var circleHeight = height/rowCount;
var x = colIndex * circleWidth;
var y = rowIndex * circleHeight;
fill(255);
ellipse(x, y, circleWidth, circleHeight);
}
}
This code draws a grid of circles, which you might do using a nested for loop. Instead, it creates a drawRow() function which draws a single row of circles, and then calls that from a drawGrid() function. The drawGrid() function loops over each row and calls the drawRow() function, which loops over each circle in that particular row.
The benefit of this is that you only ever have to worry about one loop at a time, and it also makes testing things much easier because you can directly call the "inner function" to test that it's working the way you expected.

Most efficient way to find an element in a 2-dim array using javascript

I'm using polynomial O(n^2) runtime to find all 1s. However, this approach would suffer if my 2 dimensional grow real big. It's going to eat up time. What algorithm should be used and can you refactor the code?
function findAllOnes(input) {
var s = '';
locationsOfOnes = [];
for (var y = 0; y < input.length; y++) {
s = '';
for (var x = 0; x < input[0].length; x++) {
s = s + input[y][x].toString(); // this is just for output to show it in 2 dimensional view
if (input[y][x] !== 0) {
locationsOfOnes.push({x: x, y: y})
}
}
console.log(y.toString() + '.)', s)
}
return locationsOfOnes;
}
You can use this live working code - https://jsfiddle.net/tLpa1f3s/
I don't think this can be done better than O(n^2) since you would have to travel traverse the array at least once in order to get where the value is equal to one.

first loop not working

My Inner loop seems to work fine, but once the inner loop is complete i expect the first loop to start again but it doesn't and it's not clear to me why...
if(search)
{
// loop through Revenue Arrangements
for (var x = 0; search != null && x < search.length; x++)
{
var revenue_arrangement = nlapiLoadRecord('revenuearrangement', search[x].getValue(columns[0]));
nlapiLogExecution('DEBUG', 'Revenue Arrangement Internal ID', search[x].getValue(columns[0]));
var count = revenue_arrangement.getLineItemCount('revenueelement');
for (var x = 1; x <= count; x++)
{
var rev_element_id = revenue_arrangement.getLineItemValue('revenueelement', 'transactionline', x);
if(rev_element_id)
{
nlapiLogExecution('DEBUG', 'Element Internal ID', rev_element_id);
}
}
nlapiLogExecution('DEBUG', 'End of Inner Loop);
}
}
your both loops (inner and outer) are using the same variable as counter (x)
Use different counter variables for both
if(search)
{
// loop through Revenue Arrangements
for (var x = 0; search != null && x < search.length; x++)
{
var revenue_arrangement = nlapiLoadRecord('revenuearrangement', search[x].getValue(columns[0]));
nlapiLogExecution('DEBUG', 'Revenue Arrangement Internal ID', search[x].getValue(columns[0]));
var count = revenue_arrangement.getLineItemCount('revenueelement');
for (var y = 1; y <= count; y++)
{
var rev_element_id = revenue_arrangement.getLineItemValue('revenueelement', 'transactionline', y);
if(rev_element_id)
{
nlapiLogExecution('DEBUG', 'Element Internal ID', rev_element_id);
}
}
nlapiLogExecution('DEBUG', 'End of Inner Loop);
}
}
You're reusing the x variable and the nested iteration affects the outer one. This was stated clearly in other answer, but let's extend this to point to two aspects of javascript you might be not aware of, but you should:
Javascript uses block operators {} but it does not implement block
scope. This means that a for loop does not create a new variable
scope. This is significant if you come from c/c++ background.
See more:
http://doctrina.org/JavaScript:Why-Understanding-Scope-And-Closures-Matter.html
(also see for closures, that is how outer scope affects nested function scopes).
Javascript hoists variable declarations to the beginning of a
function scope. This means both of var x are effectively declared
in the very beginning of the snippet included in the question (or
possibly even earlier).
See more:
http://www.w3schools.com/js/js_hoisting.asp
Extra var hoisting example which shows how bizzare can be its effects: http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
The above means that your code (simplified) of this:
var search = ["a","b","c","d"], count;
if(true) {
for (var x = 0; x < search.length; x++){
count = 2;
for (var x = 1; x <= count; x++){
console.log("innner", x)
}
console.log("outer", x)
}
}
is the same as this:
var search = ["a","b","c","d"], count, x = 1;
if(true) {
for (; x < search.length; x++){
count = 2;
for (; x <= count; x++){
console.log("innner", x)
}
console.log("outer", x)
}
}
That means you don't only have two loops that affect each other. You're also ignoring the 0 element of the first array (the var x = 1 in nested loop overrides var x = 0 in the outer).
Both snippets will output:
innner 1
innner 2
outer 3

Getting html elements in a for loop

This for loop does not run. This simple code is supposed to get all of the H5 elements on the page then get the "innerHTML" but the code never runs the for loop.
function myFunction() {
var x = document.getElementsByTagName("h5").length;
alert(x);
var y;
var z;
for (i = 0; i < x.length; i++) {
y = document.getElementsByTagName("h5")[i];
z = y.innerHTML;
alert(z + " this");
}
}
You're looking for a .length property on x which is itself a length number. I think you mean:
var x = document.getElementsByTagName("h5");
Or of course
for (i = 0; i < x; i++) {
Depending on what you're doing with x afterwards
var x = document.getElementsByTagName("h5").length;
// ...
for (i = 0; i < x.length; i++) {
You're calling .length twice.
The other answers are correct, but here's a little refactoring with some explanations.
function myFunction() {
// Taking out the '.length' means you have a reference to all the h5s
var x = document.getElementsByTagName("h5");
alert(x);
var y;
var z;
//Now since you're not including the .length above, this loop is correct
for (i = 0; i < x.length; i++) {
//You since x is a reference to all the h5s now you don't
//have to search for them again.
y = x[i];
z = y.innerHTML;
alert(z + " this");
}
}
The important part there is just to use one getElementsByTagName call since that's a relatively expensive function. You definitely don't want to call it in a loop if you can avoid it. Generally to write good javascript you want to reuse references to DOM Elements as much as possible since the DOM is much slower than Javascript.

Fastest way to loop through this array in Javascript on Chrome 36

I have a very big array which looks similar to this
var counts = ["gfdg 34243","jhfj 543554",....] //55268 elements long
this is my current loop
var replace = "";
var scored = 0;
var qgram = "";
var score1 = 0;
var len = counts.length;
function score(pplaintext1) {
qgram = pplaintext1;
for (var x = 0; x < qgram.length; x++) {
for (var a = 0, len = counts.length; a < len; a++) {
if (qgram.substring(x, x + 4) === counts[a].substring(0, 4)) {
replace = parseInt(counts[a].replace(/[^1-9]/g, ""));
scored += Math.log(replace / len) * Math.LOG10E;
} else {
scored += Math.log(1 / len) * Math.LOG10E;
}
}
}
score1 = scored;
scored = 0;
} //need to call the function 1000 times roughly
I have to loop through this array several times and my code is running slowly. My question is what the fastest way to loop through this array would be so I can save as much time as possible.
Your counts array appears to be a list of unique strings and values associated with them. Use an object instead, keyed on the unique strings, e.g.:
var counts = { gfdg: 34243, jhfj: 543554, ... };
This will massively improve the performance by removing the need for the O(n) inner loop by replacing it with an O(1) object key lookup.
Also, avoid divisions - log(1 / n) = -log(n) - and move loop invariants outside the loops. Your log(1/len) * Math.LOG10E is actually a constant added in every pass, except that in the first if branch you also need to factor in Math.log(replace), which in log math means adding it.
p.s. avoid using the outer scoped state variables for the score, too! I think the below replicates your scoring algorithm correctly:
var len = Object.keys(counts).length;
function score(text) {
var result = 0;
var factor = -Math.log(len) * Math.LOG10E;
for (var x = 0, n = text.length - 4; x < n; ++x) {
var qgram = text.substring(x, x + 4);
var replace = counts[qgram];
if (replace) {
result += Math.log(replace) + factor;
} else {
result += len * factor; // once for each ngram
}
}
return result;
}

Categories