Can someone explain what's going on in this for loop? - javascript

Also please include a tracetable that shows the values of each variable at each position. Thanks. When it returns true, it says that the array is a palindrome. When it returns false, it says that the array is not a palindrome. The code works, but I just need an explanation of why or how it works.
var x = readNumberOfEntries();
var w = new Array(x);
for (var y = 0; y < x; y++) {
var z = Number(prompt("Enter entry"));
w[y] = z;
}
var r = w.length;
for (var i = 0; i < (r/2); i++) {
if (w[i] !== w [r-1-i]) {
return false;
}
return true;
}
}

First for-loop fills an array of length x with user entered values.
Second for-loop checks for array like this [1,2,3,3,2,1].
So it checks wether the array is reversev in the second half.
Though because of the return the for-loop will be canceled at first run.
So if the first entry of the array equals the last it will return true, otherwise false.

Related

javascript while loop correctly iterating but for loop with same logic is not, on array with integer values and some null values in there

Iterating through a javascript array which has some data in, and some null or not defined values also, is giving funny behaviors with a for loop, but not with a while loop. It is not returning when it should and is stuck in an infinite loop
I have investigated the outputs extensively, the condition whether the number exists in the array is never evaluated to be true, only ever false, but it sometimes enters the if statement region as if it is true. It is seemingly arbitrary.
//function called within this code
function randomArrayOfIndexes() {
var randNumbArray = new Array(4);
var indexToAssign = Math.floor(Math.random() * Math.floor(4));
randNumbArray[0] = indexToAssign;
for (i = 1; i < randNumbArray.length; i++) {
indexToAssign = Math.floor(Math.random() * Math.floor(4));
while (arrayContains(randNumbArray, indexToAssign)) {
indexToAssign = Math.floor(Math.random() * Math.floor(4));
}
randNumbArray[i] = indexToAssign;
}
return randNumbArray;
}
//this works
function arrayContains(arrayin, numberIn) {
var i = arrayin.length;
while (i--) { //takes one from i so highest index is accurate on first iteration
if (arrayin[i] === numberIn) {
return true;
}
}
return false;
}
//this doesn't... not even backwards like the above iteration
function arrayIncludes(arrayin, numberIn) {
for (i = 0; i < arrayin.length; i++) {
if (arrayin[i] === numberIn) {
return true;
}
}
return false;
}
At first each function above is passed in an array with [int value, null, null, null], and a random number; when the function returns, the next null value is filled with the random number that doesn't exist in it already, so [int value, int value, null, null]... until all values are filled... the final array is filled with unique random numbers from 0 to 3, to provide an index for a piece of data in another array... to make sure that it is only used once in the program I am writing.
I would expect it to return true if the number passed in is already in there, another random number then generated outside of the broken function, and the process repeated until a unique random number is found. When it is found, the array being passed back in will be populated at the next available index, and the process repeated. This is not happening. It is getting stuck in an infinite loop, and never returning
you are just missing a var before i:
function arrayIncludes(arrayin, numberIn) {
for (var i = 0; i < arrayin.length; i++) {
// in ^ here
if (arrayin[i] === numberIn) {
return true;
}
}
return false;
}
You may also declare it before loop, like
var i;
for (i = 0; i < arrayin.length; i++) {
...
By the way, this way of generating random numbers without duplicates is very inefficient, I suggest something like having an array of 0-3 (in your current example) or 0-n and then just randomly taking items out of it. then you don't have to loop through the whole array each time you find a new number. every time you just find a random index between 0 and the length of remaining items.
Imagine that the array length is 1000, and the last item remaining is a number like 100, how many times you have to find a random number and loop through whole array till your random number is 100?
var n = 5;
var a = new Array(n);
for(var i=0;i<n;i++) a[i] = i;
var result = new Array(n);
var i = n;
while(i)
{
var index = Math.floor(Math.random() * i);
result[--i] = a[index];
a.splice(index,1);
}
document.getElementById('a').innerHTML = result;
<div id="a"></div>
You need to declare variables in you loops with for i=0. if you don't do this the variable is global and when you use the same loop variable in nested loops one can change the other.
You are using i in both loops so when you call the for loop with:
function arrayIncludes(arrayin, numberIn) {
for (i = 0; i < arrayin.length; i++) {
// etc
}
You set i back to 0 ad iterate it — this is the same i you are using in randomArrayOfIndexes so it interferes with that loop. This is a common cause of hard-to-find bugs and is hy you should always declare loop variables.
Here's the bug in it's simplest form. Notice that the out loop only runs once because i is incremented in the inner loop causing the outloop to exit early:
for (i = 0; i < 4; i++){
console.log("out loop number: ", i)
for (i = 0; i < 4; i++){
console.log("inner_loop: ", i)
}
}
If you declare the variables for for let i =, each loop gets its own version of i both loops run independently:
for (let i = 0; i < 4; i++){
console.log("out loop number: ", i)
for (let i = 0; i < 4; i++){
console.log("inner_loop: ", i)
}
}

Javascript array while loop. Comparing results: arr[len] vs arr[len-1]

Good day everyone!
I've found this great code from this site:
var points = [30,100];
document.getElementById("demo").innerHTML = myArrayMax(points);
function myArrayMax(arr) {
var len = arr.length;
var max = -Infinity;
while (len--) {
if (arr[len] > max) {
max = arr[len];
}
}
return max;
}
source: Find the min/max element of an Array in JavaScript
It really works really well and very fast. I've got a question (out of curiosity). When I tried to add (or manipulate) something, the result didn't match based from the first code. Here is the code:
var points = [30,100];
document.getElementById("demo").innerHTML = myArrayMax(points);
function myArrayMax(arr) {
var len = arr.length;
var max = -Infinity;
while (len--) {
if (arr[len-1] > max) {
max = arr[len-1];
}
}
return max;
}
I've assumed that the array[0] is the first array element, also I used post-decrement function, and yet I didn't get the expected result.
First of all, using arr[len-1] adds a new problem to the mix: Index out of bounds. This happens when the loop iterates the last element in the loop (len == 0 after len--) and you end up looking for arr[-1] which doesn't exist. Also, you're not checking anymore for the last index in the array (arr[arr.length - 1]), since len-- already substracts from the index. Like so:
var points = [30,100];
document.getElementById("demo").innerHTML = myArrayMax(points);
function myArrayMax(arr) {
var len = arr.length; // len == 2
var max = -Infinity;
while (len--) { // len == 1
// checking for arr[len - 1] the first time
// results in checking for arr[0]. arr[1] will be skipped
if (arr[len-1] > max) {
max = arr[len-1];
}
}
return max;
}
The function works well in the first place, so... Why fix what isn't broken?
Check out arithmetic operators for more info on len--.
function myArrayMax(arr) {
var len = arr.length;
var max = -Infinity;
while (len--) { // here itself you are decrementing the value of len
if (arr[len-1] > max) { // here also you are checking the previous one. Then you won't get chance to check the last array element.
max = arr[len-1];
}
}
return max;
}
// moreover you will get index out of bound exception while going in last iteration.

Comparing values between two arrays

I'm trying to set up a function that checks if a word or a text is a palindrome. To do that, it splits the text so that every letter is an element of a new array, it takes rid of the white spaces and it makes the reverse array.
Then it checks if every element of the two arrays, at the same positions, are equal. If not it returns false, if yes it returns true.
Here the function:
function palindrome(str) {
var low = str.toLowerCase();
var newArray = low.split("");
var noSpace = newArray.filter(function(val) {
return val !== " ";
});
var reverse = noSpace.reverse();
function check (a, b) {
console.log(`checking '${a}' against '${b}'`);
var partial;
var result = 1;
for (var i = 0; i < a.length; i++) {
console.log(`comparing '${a[i]}' and '${b[i]}'`);
if (a[i] !== b[i]) {
result = 0;
} else {
partial = 1;
result *= partial;
}
}
return result;
}
var result = check(noSpace, reverse);
if (result == 1) {
return true;
} else {
return false;
}
}
palindrome("r y e");
I don't know what's wrong but it seems that the function keeps on returning a true value no matter what word or text I pass to the function. What is wrong with that?
Your issue seems to be because reverse() changes the actual array as well. So doing
var reverse = noSpace.reverse();
Will reverse noSpace and assign a reference to it on the variable reverse. That is, both arrays will be the same (reversed) array.
To bypass that, I've used .slice() to create a copy of the original array, and then called .reverse() on that new array, ridding you of any conflicts.
Here's a working snippet of what it looks like:
function palindrome(str) {
var str_array = str.toLowerCase().split("");
var no_space = str_array.filter(function(val) {
return val !== " ";
});
// By applying '.slice()', we create a new array
// reference which can then be reversed and assigned
// to the 'reverse' variable
var reverse = no_space.slice().reverse();
function check(a, b) {
var partial;
var result = 1;
for(var i=0; i < a.length; i++) {
if(a[i] !== b[i]) {
// We don't need to keep
// comparing the two, it
// already failed
return 0;
} else {
// I've kept this part even though
// I don't really know what it is
// intended for
partial = 1;
result *= partial;
}
}
return result;
}
return check(no_space, reverse) === 1;
}
console.log(palindrome("a b a"));
console.log(palindrome("r y e"));
The way you have coded for palindrome is way too complicated.
But there is one problem with your code: when you do a reverse() it changes the original array as well.
So you will need to make sure that you copy it via slice().
Also you can directly send a boolean result rather than doing a 1 and 0.
At result *= partial;, 1 * 1 will always equal 1
I didn't correct your code, but here is a optimized solution for you.
function palindrom(string) {
var arr = string.split("");
var lengthToCheck = Math.floor(arr.length / 2);
for (var i = 0; i < lengthToCheck; i++) {
if (arr[i] != arr[arr.length - (1 + i)]) {
return false;
}
}
return true;
}
First I split the array after every charater of the passed String. After that I get the half of the length of the array as it's enough to check just one half.
With the for-loop I compare the first half with the second half. As soon as I found two characters that do not match I return false. In case the whole first half matches the second half of the array, the for-loop will be completed and after that true will be returned.
What's actually happening is .reverse() reverses an array in place, it then stores a reference to that array which is not what you're calling in your check() method.
Simple fix would be to change your if statement:
if (a[i] !== b.reverse()[i])

multidimensional array indexOf not working js

I'm trying to find an index of a number in a 2d array, but console gives out
Uncaught TypeError: block[((a * 10) + c)].indexOf is not a function
I think it has something to do with the way of accessing the array element, but can't seem to find the problem.
Here's the code.
var block = [];
var temp;
var del;
for(var a = 0;a < 9;a++){
for(var b = 0;b < 9;b++){
temp = parseInt(prompt("enter element number " + b + " of row number " + a));
console.log(temp);
if(temp>0){
block[a*10+b] = temp;
}else{
block[a*10+b] = [1,2,3,4,5,6,7,8,9];
}
// console.log(block[a*10+b]);
}
}
for(var a = 0;a < 9;a++){
for(var b = 0;b < 9;b++){
if(typeof(block[a][b]) == "number"){
for(var c = 0;c < 9;c++){
if(c != b){
del = block[a*10+c].indexOf(b);
block[a*10+c].splice(del,1);
}
}
}
}
}
You have a mix of data types assigned to the block array. When the user enters a value that is not numeric, you assign indeed a nested array to one of the block elements, but not so when the user enters a valid number.
From what I think you are doing (a Sudoko game?) this might be intended: the numbers are known values in the grid, the nested arrays represent a list of values that are still possible at that particular cell.
But then in the second part of your code, you should check in which of the two cases you are, as you only want to remove array elements if the value you are looking at is indeed an array. This test you can do with Array.isArray().
There are also some other issues in the second part of your script:
The expression block[a][b] is not consistent with how you have filled that array: it should be block[a*10+b] to be consistent.
the b in .indexOf(b) is wrong: you are not looking for that value, but for block[a*10+b].
the splice() is always executed, even if the indexOf returned -1. This leads to an undesired effect, because if the first argument to splice() is negative, the index really is counted from the end of the array, and still an element is removed from the array. This should not happen: you should only execute the splice if the indexOf result is non-negative.
Below I have put a working version, but in order to avoid the almost endless prompts, I have provided this snippet with a textarea where you can input the complete 9x9 grid in one go, and then press a button to start the execution of your code:
document.querySelector('button').onclick = function () {
var block = [];
var temp;
var del;
var text = document.querySelector('textarea').value.replace(/\s+/g, '');
for(var a = 0;a < 9;a++){
for(var b = 0;b < 9;b++){
temp = parseInt(text[a*9+b]); // <-- get char from text area
if(temp>0){
block[a*10+b] = temp;
}else{
block[a*10+b] = [1,2,3,4,5,6,7,8,9];
}
}
}
for(var a = 0;a < 9;a++){
for(var b = 0;b < 9;b++){
var num = block[a*10+b]; // <-- get content, fix the index issue
if(typeof num == "number"){
for(var c = 0;c < 9;c++){
if(c != b && Array.isArray(block[a*10+c])){ //<-- add array-test
del = block[a*10+c].indexOf(num); // <-- not b, but num
if (del > -1) // <-- only splice when found
block[a*10+c].splice(del,1);
}
}
}
}
}
document.querySelector('pre').textContent = 'block='+ JSON.stringify(block);
};
<textarea rows=9>
53..7....
6..195...
.98....6.
8...6...3
4..8.3..1
7...2...6
.6....28.
...419..5
....8..79
</textarea>
<button>Process</button>
<pre></pre>
Note that there are elements in block which remain null. I suppose you intended this: as you multiply a with 10, and only store 9 values per "row", there is always one index that remains untouched.
I haven't looked over your second for loop, but you can try applying similar logic there as in the snippet I've provided. The issue is that you need to create a temporary array inside the outer for loop over values of a (but NOT inside the inner, nested for loop over values of b). Inside the for loop for values of b, then, you need to push something into that temporary array (which I called temp). Then, outside of the b for loop, but before the next iteration of a, push that temporary array temp to the block array. In this way, you will generate a 2D array.
var block = [];
var del;
for(var a = 0; a < 9; a++) {
let temp = [];
for(var b = 0; b < 9; b++) {
let num = parseInt(prompt(`Enter element ${b} of row ${a}:`));
if (num > 0) {
temp.push(num);
} else {
// block[a*10+b] = [1,2,3,4,5,6,7,8,9];
temp.push(b);
}
}
block.push(temp);
}

How do I grab the two largest integers from a Javascript Array and return the value to the DOM?

I've written a solution to take a list of integers entered through a form. It works. It gives you the sum of the two largest integers and posts it in the DOM.
However, it's not very efficient for large arrays of say 1 million integers.
How can I improve this solution to be more efficient.
App.js
// This function reverses the order of the array and places the biggest numbers first
function sortNumber(a, b) {
return b - a;
}
// this function is used to ensure the user didn't enter any letters
function getArray() {
var alphaExp = /^[a-zA-Z]+$/;
// This function takes the array, orders it, adds the sum of the two largest numbers and returns the value
function sumOf(x) {
// Sort the ary with the sortNumber function
array.sort(sortNumber);
// Then we add the two biggest numbers of the array and save it to the result variable.
var result = array[0] + array[1];
// Then we share the result with the user by updating the browser
var myHeading = document.querySelector('h2');
myHeading.textContent = "The sum of your two biggest numbers is: " + result;
// Like a good student, it's important to show your work
var showYourWork = document.querySelector('h3');
showYourWork.textContent = array[0] + " + " + array[1] + " = " + result;
}
// This grabs the value of the input
var arrayField = document.getElementById('arrayField').value;
if (arrayField.match(alphaExp)) {
// Fail if user enters letters
var raiseError = document.querySelector('h5');
raiseError.textContent = 'No not letters! We want numbers!!';
} else {
var array = JSON.parse("[" + arrayField + "]");
if (arrayField.length < 2) {
// If the user enters only 1 number, tell them to enter more!
var raiseError = document.querySelector('h5');
raiseError.textContent = 'Please enter atleast two numbers seperated by commas for us to add!'
} else {
// When the user enters a list of numbers, run the sumOf function.
sumOf(arrayField);
//Make the error go away
var raiseError = document.querySelector('h5');
raiseError.textContent = '';
}
}
};
// use an eventlistener for the event (This is where the magic happens)
var subButton = document.getElementById('subButton');
subButton.addEventListener('click', getArray, false);
You don't have to sort it, just search linearly for the two biggest ones:
EDIT: the code below should work now and is asymptotically faster than the OP's code. The OP does sorting first which can be done in O(n log n), assuming a random list. My code does a linear search through the list in O(cn) with c = 2 (the two loops are not necessary but simple). The solution for ceil(n log n) = 2n with n a positive integer is 14, that is for every list longer than 14 entries the code below is faster. E.g.: for one million entries the relation is 13,815,511 to 2,000,000, more than six times faster. You can do the same thing in a single loop which halves the runtime (theoretically, but it is also a tiny bit faster because of the better locality).
function maxtwo_wrong(a){
var b1 = -Infinity;
var b2 = -Infinity;
for (var i=0; i < a.length; i++) {
if (a[i] > b1) {
b1 = a[i];
}
}
for (var i=0; i < a.length; i++) {
if (a[i] > b2 && a[i] < b1) {
b2 = a[i];
}
}
return [b1,b2];
}
EDIT-2: The code above maxtwo_wrong seems not to fit the requirements, so I wrote another one maxtwo_rightand put it below. Please, OP, tell me which one fulfills your requirements such that I can delete the wrong one.
EDIT-3: made it simpler and correct.
function maxtwo_right(a){
var b1 = -Infinity;
var b2 = -Infinity;
for (var i=0; i < a.length; i++) {
// If the current entry is bigger than variable b1
// keep the old value in the variable b2 and set b1 to the
// value of the current entry
if (a[i] > b1) {
b2 = b1;
b1 = a[i];
}
// if the current entry equals b1 set the variable b2 to
// the value of the current entry
else if(a[i] === b1){
b2 = a[i];
}
}
// return the sum of the two variables as requested
return b1 + b2;
}
I finally found some time to sit down and work this one out.
I was looking at the problem all wrong.
Here is my new solution
// This function adds the sum of the two largest integers of an array and returns the value
function topTwoInt(theArray) {
var intArray = theArray;
var highestInt = -Infinity;
var secondHighestInt = -Infinity;
var answer = 0;
//Loop through the array
for (var i=0; i < intArray.length; i++) {
//grab the biggest int and assign it to the highestInt variable;
if (intArray[i] > highestInt) {
secondHighestInt = highestInt;
highestInt = intArray[i];
}
//If the next number is equal too highestInt or greater than secondHighestInt
//Make that number become the new secondHighestInt
else if(intArray[i] === highestInt || intArray[i] > secondHighestInt) {
secondHighestInt = intArray[i];
}
}
answer = highestInt + secondHighestInt;
return answer;
};
This solution is largely inspired by #deamentiaemundi
Thanks man.

Categories

Resources