JavaScript function not working for 0 value in array - javascript

This function is meant to find the highest variable in a list of variables, which have five id letters, and one number. It works fine with all the other slots, 2, 3, 4, 5, 6, 7, 8, 9, 10, but not 1. I need another set of eyes here.
The getVer function takes the number from the id; so ImpHt1 with getVer would be 1, while getShtNm gets ImpHt.
function find_max_feat(array_input,ShtNm) {
if (String(array_input[0]).length == 1) {
var max = 0;
}
else {
var max = getVer(array_input[0]);
}
var maxver = 0
var len = array_input.length;
for (var i = 0; i < len; i++) {
if (String(array_input[i]).length > 1) {
if (getShtNm(String(array_input[i])) == ShtNm) {
if (getVer(String(array_input[i])) > maxver) {
var max = array_input[i];
var maxver = getVer(String(array_input[i]));
}
}
}
}
return max;
}
0,DmnHt1_0,AltFm1_,0,0,0,0,0,0,0
An example of the array, which is why getVer is needed.
This is for a sheet generator, to be clear, but I've been working on the entire thing for at least a few days now, maybe even a week or weeks of on and off work.
The array above is generated any time a feat is selected, and the find_max_feat array is used to find the highest version in a group; it operates off of an infinite loop since nothing else I did could get it to work the way I wanted it to.
function checkFeats() {
updateFeatsel();
t=setTimeout("checkFeats()",1000);
}
function updateFeatsel() {
curselarray = new Array();
var selinc = 1;
while (selinc <= 10) {
var selincar = selinc - 1;
var selid = document.getElementById(String('ftlst' + selinc));
if (getVer(selid.options[selid.selectedIndex].title)) {
curselarray[selincar] = selid.options[selid.selectedIndex].title;
}
else {
curselarray[selincar] = 0;
}
selinc++;
}
document.getElementById('debug1').innerHTML = curselarray.valueOf();
featSelch('hlthm','ImpHt',healthom);
featSelch('strdmgm','ImpPd',Strpdom);
featSelch('strwhtm','ImpLi',Strwhtom);
featSelch('strsltm','EnhIt',StrSltom);
featSelch('endsurm','ImpEn',EndSurom);
featSelch('endsokm','ImpDf',EndSokom);
featSelch('intelmpm','ImpMg',Intelmom);
featSelch('willsokm','ImpMs',Willsokom);
featSelch('luckrllm','ImpLu',Lukrllom);
featSelch('luckpntm','EnhLu',Lukpntom);
featSelch('hlthbn','DmnHt',0);
featSelch('strbn','SupSt',0);
featSelch('luckbn','DmnLu',0);
featSelch('endbn','Armor',0)
document.getElementById('debug2').innerHTML = find_max_feat(curselarray,'DmnHt');
updateAmounts();
}
function featSelch(sid,fshtnm,defval) {
return document.getElementById(sid).innerHTML = getFeatvalue(fshtnm,defval);
}

That is because you are initialising max using getVer(array_input[0]) instead of array_input[0]. If the first item is the highest and has the version number zero, the initial value is used.
Change this:
var max = getVer(array_input[0]);
into:
var max = array_input[0];

Related

Print every value within range iterator generator function javascript

Iterator should print every value within range but its only printing alternate nos.
function iterator(rangeStart, rangeEnd) {
if (rangeStart == 0 && rangeEnd == 0) {
return null;
}
var iterate = function*(start = 0, end = 5, step = 1) {
let iterationcount = 0;
for (let i = start; i <= end; i += step) {
yield i;
iterationCount = i;
}
return iterationCount;
}
var values = iterate(rangeStart, rangeEnd);
var tmp = [];
while (values.next().value != undefined) {
tmp.push(values.next().value);
}
return tmp.join(",");
}
console.log(iterator(0, 10))
expected
[0,1,2,3,4,5,6,7,8,9,10]
Result
[1,3,5,7,9,10]
Every call to next will consume a value from the iterator, so the while condition is consuming a value that will therefore not get into tmp.
But... JavaScript allows you to consume values in much easier ways. For instance with Array.from or spread syntax you can collect all values from the iterator into an array.
Not your question, but:
iterationCount serves no purpose in your code, so just drop that part.
Why would the function behave differently when both range start and end are 0 than when start and end are both 10? I would remove that case. When the range end would be less than the start, it would make sense to exit, but that will happen anyway without any if statement.
The name iterator for your function is somewhat misleading, as the return value is not an iterator, but a comma separated string. I would therefore call it rangeToCsv
function rangeToCsv(rangeStart, rangeEnd) {
var iterate = function*(start = 0, end = 5, step = 1) {
for (let i = start; i <= end; i += step) {
yield i;
}
}
var values = iterate(rangeStart, rangeEnd);
return Array.from(values).join(",");
}
console.log(rangeToCsv(0, 10))

Bird Watcher Exercism Javascript Solution - counter not counting

I'm trying to figure out an exercise from Exercism's Javascript track. It is an exercise using for loops called Bird Watcher.
The instructions say to initialize a function called birdsInWeek that takes two arguments. First is an array 'birdsPerDay', and the second is 'week'. Given the birdsPerDay array, the function is supposed to count the total number of birds seen in the specified week. So, if 'week' = 1, for example, the corresponding indexes of 'birdsPerDay' to add together would be 0 - 6, and so on and so forth.
I have tested my code using the provided test cases and in the Chrome console. I tried logging some values to understand where the bug is, but I can't figure out why my counter (named 'totalBirdsInSpecifiedWeek'), which is initialized to '0' is staying at '0' instead of adding the corresponding indexes of 'week' together and return the correct 'totalBirdsInSpecifiedWeek'. I have tried changing the placement of the return statement as well, but that didn't result in any change.
Below is the code I have written:
export function birdsInWeek(birdsPerDay, week) {
let totalBirdsInSpecifiedWeek = 0
if (week === 1) {
for (let i = 0; i < birdsPerDay[7]; i++) {
totalBirdsInSpecifiedWeek += birdsPerDay[i];
}
return totalBirdsInSpecifiedWeek;
} else {
for (let i = week * 7 - 7; i < birdsPerDay[week * 7]; i++) {
totalBirdsInSpecifiedWeek += birdsPerDay[i];
}
return totalBirdsInSpecifiedWeek;
};
}
Where did I go wrong?
birdsPerDay[7] this means values of birdsPerDay array at index 7 of the array
so the condition would loop checking if i is lesser than that value sometimes it would even hit the NaN so the idea is to just check on either length or index of the array to get an accurate response ..
Per the commenter #gog, I changed the 4th and 9th lines of code to correct the stopping condition in each of the for loops so they are written as indexes of the 'birdsPerDay' array and instead just numerical values.
export function birdsInWeek(birdsPerDay, week) {
let totalBirdsInSpecifiedWeek = 0
if (week === 1) {
for (let i = 0; i < 7; i++) {
totalBirdsInSpecifiedWeek += birdsPerDay[i];
}
return totalBirdsInSpecifiedWeek;
} else {
for (let i = week * 7 - 7; i < week * 7; i++) {
totalBirdsInSpecifiedWeek += birdsPerDay[i];
}
return totalBirdsInSpecifiedWeek;
}; return totalBirdsInSpecifiedWeek;
}
I found the exercise, according to the problem posed, I think this is the solution.
bird-watcher - exercism
Explanation, the array is divided by the days of the week, then the array is divided by that amount from 0 to 6 (Monday to Sunday), then I used a nested "for" to iterate over the corresponding week, I used another "for" to do the addition, return the value from the function and return the result.
let countsbirdsPerDay = [2, 5, 0, 7, 4, 1, 3, 0, 2, 5, 0, 1, 3, 1];
let userWeek = 2;
const birdsInWeek = (birdsPerDay, week) => {
let segmentWeek = Math.round(birdsPerDay.length / week);
let total = 0;
for (let i = 0; i < week; i++) {
views = birdsPerDay.slice(i * segmentWeek, segmentWeek * (i + 1));
if ((i + 1) == week) {
for (let x = 0; x < views.length; x++) {
total = total + views[x];
}
}
}
return total;
}
console.log(birdsInWeek(countsbirdsPerDay, userWeek));

recursive backtracking for sudoku?

Im trying to make a sudoku solver algorithm to practice recursion and backtracking, so made this function 'backtrack' which is the main function that's supposed to solve it , and four other 'utility/helper' functions;the first one is 'getSubGrid' which returns the subgrid where the current number belongs,and then 'getColumn' which returns the column where the current number belongs, and 'getRow' which returns the row where the current number belongs, and the last helper function is 'subGridIncludes' to check whether a subgrid includes a specific number or not.The problem is that for some boards, this code works and solve them, but for some other boards it doesn't and it gives me 'too much recursion' error.Note that i tried to calculate how many recursive calls each board requires and i found that the boards that worked required less than 6000 calls , but the one of the boards that didnt work required more than 10000 call before i got the message 'too much recursion',and i want to know if the error is because i didnt set a base case that was present in the boards that were not solved and not present in the boards that were solved, or is it because the board is just big and i need to rewrite the script in a way that requires the least amount of recursive calls.
these are examples of the boards that were succesfully solved:
board 1:
[
[7,8,0,4,0,0,1,2,0],
[6,0,0,0,7,5,0,0,9],
[0,0,0,6,0,1,0,7,8],
[0,0,7,0,4,0,2,6,0],
[0,0,1,0,5,0,9,3,0],
[9,0,4,0,6,0,0,0,5],
[0,7,0,3,0,0,0,1,2],
[1,2,0,0,0,7,4,0,0],
[0,4,9,2,0,6,0,0,7]
]
board 2:
[
[0,2,0,0,0,8,0,0,4],
[0,9,0,1,0,0,6,0,0],
[0,0,3,0,0,0,0,1,0],
[9,0,1,4,0,0,0,0,8],
[0,0,0,0,0,0,3,0,2],
[0,0,5,0,8,3,0,0,7],
[0,0,4,0,0,0,9,2,0],
[7,0,0,3,0,0,8,5,0],
[0,0,0,2,5,6,4,0,3]
]
and this is an example of a board that the function didnt solve:
[
[1,0,0, 0,5,0, 0,4,0],
[0,0,0, 9,0,0, 0,0,1],
[0,0,0, 0,0,3, 8,0,0],
[0,5,0, 8,0,2, 4,0,0],
[0,0,0, 0,0,0, 0,0,0],
[4,0,0, 0,0,0, 7,5,3],
[5,0,0, 3,0,0, 0,6,0],
[0,2,0, 0,0,1, 3,7,0],
[0,6,0, 4,0,9, 0,0,0]
]
and this is the code:
let lastPopped; // variable to keep track of the last changed value
let addedVals = [[]]; // array of arrays to keep track of the indexes where the values were changed on each row,where the index of each subarray corresponds to the index of the row
backtrack()
function backtrack(currentRowIndex = 0, currentRow = board[currentRowIndex], testValue = 1, i = 0) {
// testValue is a value put under test to check if its included in the row, column,subgrid
if (currentRowIndex === board.length) {
// this condition checks the board is finished ,if so it stops the execution of the function.
return
} else if (i === currentRow.length) {
// this condition checks if we reached the end of the current row ,if so it takes us to the next row.
lastPopped = undefined
addedVals.push(new Array())
backtrack(currentRowIndex + 1, currentRow = board[currentRowIndex + 1], testValue = 1, i = 0)
} else if (testValue > 9) {
// this condition checks if the testValue is greater than 9,if so we know that we should set the current value to 0 and we backtrack to the previous value.
currentRow[i] = 0
if (i === 0 || (addedVals[currentRowIndex].length === 0)) {
// this condition checks whether we are at the start of a row or the previous values are original, if so we backtrack to the previous row.
lastPopped = addedVals[currentRowIndex - 1].pop()
backtrack(currentRowIndex - 1, currentRow = board[currentRowIndex - 1], testValue = board[currentRowIndex - 1][lastPopped] + 1, i = lastPopped)
} else {
// if the previous condtion is not satisfied we backtrack to the previous value plus one in the same row.
lastPopped = addedVals[currentRowIndex].pop()
backtrack(currentRowIndex, currentRow = board[currentRowIndex], testValue = currentRow[lastPopped] + 1, i = lastPopped)
}
} else {
if (currentRow[i] === 0 || i === lastPopped) {
// this condition checks if the current value is a value that was not original or equal to zero.
if (!getColumn(currentRow[i], currentRowIndex).includes(testValue) && !subGridIncludes(0, testValue, getSubGrid(currentRow[i], currentRowIndex)) && !getRow(currentRow[i], currentRowIndex).includes(testValue)) {
//this condition checks whether the testValue is included in the row, column,subgrid,if so it assigns it to the current index,and pushes the index to the addedVals array to indicate that the current index's value has bee changes and keep trakc of it for comming purposes
currentRow[i] = testValue;
addedVals[currentRowIndex].push(i);
if (currentRow[i] != 0 && i === 8) {
//this condition enables us to move to the next row when needed
lastPopped = undefined
addedVals.push(new Array())
backtrack(currentRowIndex + 1, currentRow = board[currentRowIndex + 1], testValue = 1, i = 0)
} else {
//this condition enables us to move to the next index when needed
backtrack(currentRowIndex, currentRow = board[currentRowIndex], testValue = 1, i + 1)
}
} else {
//this condition adds 1 to the test value with each call.
backtrack(currentRowIndex, currentRow = board[currentRowIndex], testValue + 1, i)
}
} else {
if (currentRow[i] != 0 && i === 8) {
//this condition enables us to move to the next row when needed
addedVals.push(new Array())
backtrack(currentRowIndex + 1, currentRow = board[currentRowIndex + 1], testValue = 1, i = 0)
} else {
//this condition enables us to move to the next index when needed
backtrack(currentRowIndex, currentRow = board[currentRowIndex], testValue = 1, i + 1)
}
}
}
}
for (property in board) {
console.log(".", JSON.stringify(board[property]));
}
//this function checks whether a subgrid includes a specific number or not
function subGridIncludes(index, value, subgrd) {
if (index === subgrd.length) {
return false
} else {
return subgrd[index].includes(value) ? true : subGridIncludes(index + 1, value, subgrd)
}
}
//this function returns the subgrid where the element belongs.
function getSubGrid(num, index) {
let arr = new Array(3).fill([])
let oneDimentionalIndex, twoDimentionalIndex, tdiSub, odiSub;
let [rightOrBelow, leftOrAbove, rightOrBelowAndleftOrAbove] = [[0, 3, 6], [2, 5, 8], [1, 4, 7]];
for (let j = 0; j < board[index].length; j++) {
if (board[index][j] === num) {
oneDimentionalIndex = index;
twoDimentionalIndex = j;
break
}
}
rightOrBelow.includes(oneDimentionalIndex) ? odiSub = 0 : leftOrAbove.includes(oneDimentionalIndex) ? odiSub = 2 : rightOrBelowAndleftOrAbove.includes(oneDimentionalIndex) ? odiSub = 1 : null;
rightOrBelow.includes(twoDimentionalIndex) ? tdiSub = 0 : leftOrAbove.includes(twoDimentionalIndex) ? tdiSub = 2 : rightOrBelowAndleftOrAbove.includes(twoDimentionalIndex) ? tdiSub = 1 : null;
arr = arr.map((_, ind) => board[(oneDimentionalIndex - odiSub) + ind].slice(twoDimentionalIndex - tdiSub, ((twoDimentionalIndex - tdiSub) + 3)))
return arr
}
//this function returns the column where the element belongs.
function getColumn(num, index) {
let twoDimentionalIndex;
let column = new Array(board.length);
for (let j = 0; j < board[index].length; j++) {
if (board[index][j] === num) {
twoDimentionalIndex = j;
break
}
}
for (let i = 0; i < board.length; i++) {
column[i] = board[i][twoDimentionalIndex];
}
return column
}
//this function returns the row where the element belongs.
function getRow(num, index) {
let oneDimentionalIndex;
let row = new Array(board.length);
for (let j = 0; j < board[index].length; j++) {
if (board[index][j] === num) {
oneDimentionalIndex = index;
break
}
}
for (let i = 0; i < board.length; i++) {
row[i] = board[oneDimentionalIndex][i];
}
return row
}
The code obviously has a lot of violations of the DRY principle because i havent had much practice with code cleaning,so im sorry.

Set a range of numbers as a variable (Javascript)

Let's say I want a variable to contain numbers from 1 to 100.
I could do it like this:
var numbers = [1,2,3,4,...,98,99,100]
But it would take a bunch of time to write all those numbers down.
Is there any way to set a range to that variable? Something like:
var numbers = [from 1, to 100]
This might sound like a really nooby question but haven't been able to figure it out myself. Thanks in advance.
Store the minimum and maximum range in an object:
var a = {
from: 0,
to: 100
};
In addition to this answer, here are some ways to do it:
for loop:
var numbers = []
for (var i = 1; i <= 100; i++) {
numbers.push(i)
}
Array.prototype.fill + Array.prototype.map
var numbers = Array(100).fill().map(function(v, i) { return i + 1; })
Or, if you are allowed to use arrow functions:
var numbers = Array(100).fill().map((v, i) => i + 1)
Or, if you are allowed to use the spread operator:
var numbers = [...Array(100)].map((v, i) => i + 1)
However, note that using the for loop is the fastest.
You can easily create your own, and store only the limits:
function Range(begin, end) {
this.low = begin;
this.hi = end;
this.has = function(n) {
return this.low <= n <= this.hi;
}
}
// code example
var range = new Range(1,100);
var num = 5;
if (range.has(num)) {
alert("Number in range");
}
Supported in all modern browsers including IE9+.
var numbers = Array.apply(null,Array(100)).map(function(e,i){return i+1;});
For what it's worth, #MaxZoom had answer that worked for my situation. However, I did need to modify the return statement to evaluate with && comparison. Otherwise appeared to return true for any number.
function Range(begin, end) {
this.low = begin;
this.hi = end;
this.has = function(n) {
//return this.low <= n <= this.hi;
return ( n >= this.low && n <= this.hi );
};
}
// code example
var alertRange = new Range(0,100);
var warnRange = new Range(101, 200);
var num = 1000;
if (alertRange.has(num)) {
alert("Number in ALERT range");
//Add Alert Class
}
else if (warnRange.has(num)) {
alert("Number in WARN range");
//Add Warn Class
}
else{
alert("Number in GOOD range")
//Default Class
}
Python
# There can be two ways to generate a range in python
# 1)
a = [*range(5)]
print(a)
#[0, 1, 2, 3, 4]
# 2)
a = [*range(5,10)]
print(a)
#[5, 6, 7, 8, 9]
Javascript
// Similar pattern in Javascript can be achieved by
let a;
// 1)
a = [...Array(5).keys()]
console.log(a) //[0, 1, 2, 3, 4]
// 2)
a = [...Array(5).keys()].map(value => value + 5);
console.log(a) //[5,6,7,8,9]

Assigning value to id only once

I've a problem that has been bugging me for a while now.
I have 14 divs each which must be assigned a random ID (between 1 and 14) each time the page loads.
Each of these divs have the class ".image-box" and the format of the ID I'm trying to assign is 'box14'
I have the JS code working to assign random IDs but I'm having trouble not getting the same ID to assign twice.
JavaScript
var used_id = new Array();
$( document ).ready(function() {
assign_id();
function assign_id()
{
$('.image-box').each(function (i, obj) {
random_number();
function random_number(){
number = 2 + Math.floor(Math.random() * 14);
var box_id = 'box' + number;
if((box_id.indexOf(used_id) !== -1) === -1)
{
$(this).attr('id',box_id);
used_id.push(box_id);
}
else
{
random_number();
}
}
});
}
});
Thanks for your help,
Cheers
Mmm, random...
Instead of using a randomly generated number (which, as your experiencing, may randomly repeat values) just use an incrementally-updated counter when assigning IDs.
function assign_id() {
var counter = 0;
$('.image-box').each(function (i, obj) {
$(this).attr('id','image-box-' + counter++); }
});
}
I think this is what you want and DEMO
$(document).ready(function() {
assign_id();
});
function assign_id() {
var numberOfDiv = $('.image-box').length;
var listOfRandomNumber = myFunction(numberOfDiv);
$('.image-box').each(function(i, obj) {
$(this).attr("id",listOfRandomNumber[i]);
});
};
//Getting List Of Number contains 1 to the number of Div which is
//14 in this case.
function myFunction(numberOfDiv ) {
for (var i = 1, ar = []; i < numberOfDiv +1 ; i++) {
ar[i] = i;
}
ar.sort(function() {
return Math.random() - 0.5;
});
return ar;
};
I would suggest to have a global array like u have for user_id and push assigned div ids into array. Then you can check before assigning random id to div. If it is assigned use different one.
Hope this helps.
Cheers.
First how you'd use my implementation:
var takeOne = makeDiminishingChoice(14);
In this case, takeOne is a function that you can call up to 14 times to get a unique random number between 1 and 14.
For example, this will output the numbers between 1 and 14 in random order:
for (var i = 0; i < 14; i++) {
console.log(takeOne());
}
And here is the implementation of makeDiminishingChoice itself:
var makeDiminishingChoice = function (howMany) {
// Generate the available choice "space" that we can select a random value from.
var pickFrom = [];
for (var i = 0; i < howMany; i++) {
pickFrom.push(i);
}
// Return a function that, when called, will return a value from the search space,
// until there are no more values left.
return function() {
if (pickFrom.length === 0) {
throw "You have requested too many values. " + howMany + " values have already been used."
}
var randomIndex = Math.floor(Math.random() * pickFrom.length);
return pickFrom.splice(randomIndex, 1)[0];
};
};
It's better to use incremental values(or something like (new Date).getTime()) if all you want to do is assign unique values. But if, for some reason, you must have randomly-picked values(only from 1-14) then use something like this to pick unique/random values
var arrayId = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
function getRandomId(array) {
var randomIndex = Math.floor(Math.random() * (array.length));
var randomId = array.splice(randomIndex, 1);
return randomId[0];
}
Now getRandomId(arrayId) would return a randomly picked value from your array and then remove that value so that it is not repeated.

Categories