Javascript undefined array in function - javascript

I've written a function that takes plevel (integer) and slevel (array of strings of numbers) and finds the smallest difference between plevel and a value in slevel. However, when I run the script, it is unresponsive and the debugger says that diff is undefined.
var findDiff = function findDiff(plevel, slevel) {
var diff = new Array();
for (i=0; i<=slevel.length; i++) {
sleveli = parseInt(slevel[i]);
diff.push(Math.abs(plevel-sleveli));
}
if (diff.length > 1){
diff.sort(function(a, b){return a-b});
return diff[0]
}
else{
return diff[0];
}
}
The function is invoked here:
var matches = new Array();
var newFetch = Data.find().fetch();
for(i = 0; i <= newFetch.length; i++ ){
pointsMatch = 0
var difference = findDiff(newFetch[i].level, spec.level);
pointsMatch -= (difference*3);
matches.push([newFetch[i], pointsMatch])
}
console.log(matches)
Data is a mongoDB collection. spec.level is an array of strings of numbers stored as a property in an object.

I would like to point out name space pollution, which may cause serious troubles. In my understanding, you have two cases of namespace pollution, one of it creates an endless loop.
You have actually an inner an outer loop, separated by a function. Your outer for loop:
for(i = 0; i <= newFetch.length; i++ ){
pointsMatch = 0
...
And then your inner for loop:
for (i=0; i<=slevel.length; i++) {
sleveli = parseInt(slevel[i]);
...
Because of the missing var before i, both for loop definitions are actually like this:
for (window.i=0; ...
So the inner loop overwrites the variable i the outer loop depends on to terminate. i is "polluting" namespace.
The second case is harmless:
sleveli = parseInt(slevel[i]);
Because of the missing var, this results in fact in
window.sleveli = parseInt(slevel[i]);
Better would be
var sleveli = parseInt(slevel[i]);
But this is a time bomb.
I suggest you add var to the definitions of i in the for loop.

I think the people in the comments are right; we need to see some more of your input to debug this properly. But you can simplify your code a lot by tracking the mins as you go:
var findDiff = function findDiff(plevel, slevel) {
var min = Number.MAX_SAFE_INTEGER;
for (i=0; i<slevel.length; i++) {
sleveli = parseInt(slevel[i]);
var diff = Math.abs(plevel-sleveli);
min = Math.min(min, diff)
}
return min;
}
var a = ["1", "2", "10", "17"]
var p = 6
// We're expecting 4 as the min diff
console.log(findDiff(p, a))
// ...prints out 4 :-)
http://repl.it/ceX
As Omri points out, use < not <= in your for loop.
Note - Number is not always available -- see here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
You could alternatively set the initial min to something suitably large for your likely data, like 2^10

Related

Can you call a for loop in a forEach method in Javascript?

First of all, I'm a total beginner in coding and have started a few weeks back, as an persona/intellectual challenge.
I want to know why do I get a null array in this simple script. I think it has something to do with var "i", but I can't find where the error is.
function DivEsc() {
var ssIn = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Input");
var ssOut = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Output");
var esc = ssIn.getRange(1,3).getValue(); //EscaƱos en reparto
var i = 0;
var arr = [400, 200,100,50];
var newArr = []
newArr = arr.forEach(num => {
for (var i = 1; i <= esc; i++){
return (num/i)
// newArr.push(num)
}
newArr.push(num/i)
}
)
Logger.log(newArr)
}
Array.prototype.forEach does not return a value, newArr will therefore become undefined. JavaScript is a dynamic language where the reassignment of values - even if they don't have the same type - is possible.
Further you return in the first iteration of the for loop, meaning that only the value for num / 1 will be calculated; probably not what you want.
// newArr is now undefined!
newArr = arr.forEach(num => {
for (var i = 1; i <= esc; i++){
// If you return a value here, the loop will stop after the first round with i = 1!
return (num/i)
// newArr.push(num)
}
newArr.push(num/i)
}
)
You could just directly push into newArr to make it work.
arr.forEach(num => {
for(var i = 1; i <= esc; i++) {
newArr.push(num / i);
}
)
If you want to learn more to try out different ways to implement your algorithm, look into JavaScript's functional array methods as e.g. Array.prototype.map and Array.prototype.reduce.
On a side note: Try using an editor/IDE that handles formatting code for you. In your snippet the formatting (e.g. end of the forEach call) makes it hard to reason about the code.

Why does this loop terminate partway through?

I'm trying to write a program to find the smallest common multiple of the provided parameters that can be evenly divided by both, as well as by all sequential numbers in the range between these parameters.
The range will be an array of two numbers that will not necessarily be in numerical order.
For example, for 1 and 3 - find the smallest common multiple of both 1 and 3 that is evenly divisible by all numbers between 1 and 3.
Why does the loop stop at i = 510,000 (or something close to that) instead of 7,000,000, as I set it?
I also have a screenshot with the output:
function smallestCommons(arr) {
var start;
var finish;
var something;
if(arr[0] < arr[1]){start = arr[0]; finish = arr[1];}else{
start = arr[1]; finish = arr[0];
}
for(var i = finish;i <= 7000000;i++){
var boolea = true;
for(var j = start;j <= finish;j++){
if(i % j !== 0){boolea = false;break;} // 2 % 1
}
if(boolea)return i;
something = i;
}
console.log("final i = " + i);
return 0;
}
Try to add this at the beginning of your loop
// noprotect
it must be that jsbin is forcing your code to exit from the loop. See source

how can i make my function more efficient?

hey guys i wrote a function that compares array values and returns the minimum value but i want to know if there are ways to make it more efficient like iterating through all arrays (using one loop) and putting the results in a new array or making individual arrays sub-arrays of a single array, etc. Also the function provides the correct output but prints the answer three times:
var nums1 = [-7528819, 3927361, -6398192];
var nums2 = [1777100, -2299720, -5566643];
var nums3 = [7188445, 3724971, 7699332];
var nums4 = [-8432528, -159836, -1604959];
var nums5 = [2764889, 4681472, 701396];
var nums6 = [-5073513, 599535, 4388457];
var nums7 = [8689640, 8028586, 1022322];
var nums8 = [-1088592, 1211232, -7868192];
var nums9 = [-5848613, -4945165, 631213];
var nums10 = [3218429, -833619, -1495854];
var nums11 = [8007060, 1637562, -7568493];
var nums12 = [-8391131, -6585338, 131787];
var nums13 = [-3957775, -9396892, -6143241];
var nums14 = [-6258442, -7829421, 3696922];
var nums15 = [2136598, 4935467, -1621605];
var nums16 = [-7162005, 9861954, 8977930];
var nums17 = [7226452, 8551594, 7006517];
var nums18 = [-1751226, -2536997, -1782251];
var nums19 = [380582, 1614389, 3272584];
var nums20 = [-8988205, -5167181, -7561034];
var nums21 = [-484059, -7160121, 4076528];
var nums22 = [1947448, -5551253, 7491190];
var numsLength = nums1.length;
var i = 0;
var minNum;
function test(arr) {
for (i; i < numsLength; i++) {
if (arr[0] < arr[1] && arr[2]) {
minNum = arr[0];
} else if (arr[1] < arr[2] && arr[0]) {
minNum = arr[1];
} else if (arr[2] < arr[1] && arr[0]) {
minNum = arr[2];
}
console.log(minNum);
}
}
test(nums1);
You could just use Math.min function.
console.log(Math.min.apply(null, nums1));
Look at his snippet of code and read inline comments:
var nums = [];
// I'm pushing only 3 sets of data, but there can be any number
// Also there can be any number of elements in each array as you can see
nums.push([-7528819, 3927361, -6398192]);
nums.push([1777100, -2299720, -5566643, 380582]);
nums.push([7188445, 3724971, 7699332, 1947448, -5551253, 7491190]);
function produceResults(nums) {
var i,
results = [];
// gathering results
for (i = 0; i < nums.length; i++) {
results.push(Math.min.apply(null, nums[i]));
}
return results;
}
console.log(produceResults(nums));
So 2 suggestions:
use more dynamic structure (array of arrays) instead of
defining 22 arrays.
use built in JS functions and components (Math.min)
Unrolling a loop is actually the most efficient implementation of a loop in most cases. However, practically speaking, unrolling a loop isn't usually feasible. With a small, fixed-size array, like those you have here, each permutation of the loop is obvious, and if your goal is raw speed you can't get much more efficient than what you have. That being said, the loop in your function is useless, as others have pointed out., because you've essentially unrolled the loop already. Also the syntax of the if statement is incorrect, and you are not handling the case where values in the array are equal. For fixed arrays of size three you want something more along the lines of...
if (val1 <= val2 && val1 <= val3) {
minVal = val1;
} else if (val2 <= val1 && val2 <= val3) {
minVal = val2;
} else minVal = val3;
Now if you want to do an arbitrary search for the min value of any size array you would do something similar, but using a loop, like...
var minVal = null;
for (var i = 0; i < arr.length; i++) {
if (minVal === null || minVal > (val = arr[i]))
minVal = val;
}
Depending on what you actually want to accomplish, and the size of the array, it might make sense to sort the array and rerurn the min (0 index) from the sorted array. If you go that route, start with a google search for "sort algorithms"

javascript finding biggest number in array not working

i'm filling an array from the input fields and i need to find the biggest number in that array.
Using Math.max(myData) gives me NaN error and when i'm using the "if" statement,sometimes it works and sometimes it doesn't.
Example: if i have 40 and 100 in array ,it gives me 40 as bigger number,but when i have 500 than it works fine.
if i want to make Math.max to work i need to make a new function that converts string into numbers,right?
my code,so you can see where is the mistake.
function Data() {
var h = 0;
var secnd = 1;
var najBr = 0;
for (var i = 0; i < valGrup2; i++)
{
var first = 1;
myDataName[i] = document.getElementById('ime' + secnd).value;
for (var j = 0; j < val2; j++)
{
myData[h] = document.getElementById("inputpolja" + first + secnd).value;
if(myData[h]>najBr){
najBr=myData[h];
}
myDataValue[h] = document.getElementById("inputpolja" + first + secnd).value;
h++;
first++;
}
secnd++;
}
//najBr=Math.max(myData);
console.log(najBr);
Math.max accepts only plain numbers, not an array.
Use this:
function getMaxOfArray(numArray) {
return Math.max.apply(null, numArray);
}
Math.max takes multiple arguments, not an array of the numbers. You can use Function#apply() to have it treat the array as a list of arguments:
Math.max.apply(null /* the context */, myData)

Writing a recursive function which iterates through an unknown depth of nested loops

Given an array of values:
var values = new Array();
array.push(2);
array.push(3);
array.push(4);
I'd like to create an iterative function which can store every possible combination of values, for any length of array.
For example, in this case the possible values would be (1,1,1)(1,1,2)(1,1,3)(1,1,4)(1,2,1)(1,2,2)(1,2,3)(1,2,4)(2,1,1)(2,1,2)(2,1,3)(2,1,4)(2,2,1)(2,2,2)(2,2,3)(2,2,4)
I know that to do this I need to use an recursive function, which will go a level deeper and call the function again if the maximum depth has not been reached...
I know where to start is (probably, I think)
function iterativeLoop(level, depth) {
for(var i = 0; i < values.length; i++) {
if(level < depth) {
iterativeloop(level+1, depth);
}
else if (level=depth) {
}
}
}
I'm not sure how I can access the 'upper' levels once the function is called deeper though... i.e. I'm not sure how to access (1,2,4) and not just (?,?,4)
I hope that makes sense?
(Sorry I know my title isn't very good, I couldn't think how to concisely explain it)
I'm not sure how I can access the 'upper' levels once the function is called deeper though... i.e. I'm not sure how to access (1,2,4) and not just (?,?,4)
You will need to pass them on, e.g. in an array.
for(var i = 0; i < values.length; i++)
This should not be the outer iteration to perform, unless you want to construct a two-dimensional array of results in a simple nested loop (see below). Instead, you want value.length to be the depth you are recursing to. On every recursion level, you will iterate from 1 to values[level] then. And instead of passing a level, we will pass an array of the current state (the question marks from above) whose length is the level.
var values = [2,3,4];
function recurse(state) {
var level = state.length;
var depth = values.length;
if (level == depth) {
console.log.apply(console, state); // or whatever you want to do
} else {
for (var i=1; i<=values[level]; i++) {
state.push(i); // save current question mark
// notice state.length = level + 1 now
recurse(state); // enter next level
state.pop(); // delete it after we're so state doesn't grow infinitely :-)
}
}
}
recurse([]);
If you want to use your iteration over the values, you can do so by adding more and more states to a result array (growing by one value each level), which in the end will contain all possible combinations:
var values = [2,3,4];
var result = [[]]; // one empty state at level 0
for (var i=0; i<values.length; i++) {
var reslen = result.length,
val = values[i];
var mult = []; // will become the new result with a length of (reslen * val)
for (var j=0; j<reslen; j++) {
for (var k=1; k<=val; k++) {
var state = result[j].slice(); // make a copy
state.push(k);
mult.push(state);
}
}
result = mult;
}
// logging the `result` on each level will show us
// 0 - [[]]
// 1 - [[1],[2]]
// 2 - [[1,1],[1,2],[1,3],[2,1],[2,2],[2,3]]
// 3 - [[1,1,1],[1,1,2],[1,1,3],[1,1,4],[1,2,1],[1,2,2],[1,2,3],[1,2,4],[1,3,1],[1,3,2],[1,3,3],[1,3,4],[2,1,1],[2,1,2],[2,1,3],[2,1,4],[2,2,1],[2,2,2],[2,2,3],[2,2,4],[2,3,1],[2,3,2],[2,3,3],[2,3,4]]
You can see how this is similar to #Jason's approach.
You don't need recursion since the length of the arbitrary data set is defined at the beginning at runtime:
var numbers = [2,3,4];
var result_array = [];
var num_product = 1;
var i=0, j=0, k=0; // iterators
for (i=0; i<numbers.length; i++) {
num_product *= numbers[i];
}
for (i=0; i<num_product; i++) {
result_array.push([]);
}
for (i=0; i<result_array.length; i++) {
product = 1;
for (j=0; j<numbers.length; j++) {
k = (Math.floor(i/product)%numbers[j]) + 1;
product *= numbers[j];
result_array[i][j] = k;
}
}
tested and functional for any number of array elements.
A side-by-side benchmark shows this code to be significantly faster than the recursive code - if you are able to avoid recursion (e.g. you know enough information up front to be able to define the whole problem) then it's better to do so, and the problem as currently defined allows you to do that. If you're just trying to learn about recursion, then this isn't very helpful to you :)

Categories