Values concatenating inside if condition - javascript

Edit: For the sake of simplicity, consider following code:
var z = {x: 1, y: 1};
console.log(z.x+5 + ' ' + z.y+5);
Why output is (6,15) instead of (6,6)?
Before edit: I have following function:
function findPath(startX, startY, goalX, goalY){
var queue = [],
candidates = [],
path = [];
queue.push({x: startX, y: startY, searchDistance: 0, hasBeenSearched: true});
fillQueue();
function fillQueue(){
setInnerHTML(queue[0].x, queue[0].y, '.');
for(var i=-1; i<=1; i++){
if(queue[0].x + i < 0 || queue[0].x + i > boardHeight - 1){
continue;
}
for(var j=-1; j<=1; j++){
if(queue[0].y + j < 0 || queue[0].y + j > boardWidth - 1){
continue;
}
if(i == 0 && j == 0){
continue;
}
if(cells[queue[0].x + i][queue[0].y + j].type.blockMovement == true || findCell(queue[0].x + i, queue[0].y + j).hasBeenSearched == true){
console.log(queue[0].x + i + ' ' + queue[0].y + j)
continue;
}
if((queue[0].x + i == goalX) && (queue[0].y + j == goalY)){
setInnerHTML(queue[0].x + i, queue[0].y + j, '.');
candidates.push(queue[0]);
candidates.push({x: queue[0].x + i, y: queue[0].y + j, searchDistance: queue[0].searchDistance + 1, hasBeenSearched: true});
//fillPath();
return path;
}
queue.push({x: queue[0].x + i, y: queue[0].y + j, searchDistance: queue[0].searchDistance + 1, hasBeenSearched: true});
}
}
candidates.push(queue.shift());
if(queue.length > 0){
setTimeout(fillQueue, 0);
}else{
return 'no path found';
}
function findCell(x,y){
for(var i=0; i<queue.length; i++){
if(queue[i].x == x && queue[i].y == y){
return queue[i];
}else if(i == queue.length - 1 && (queue[i].x != x || queue[i].y != y)){
return {hasBeenSearched: false};
}
}
}
}
}
It is part of pathfinding algorithm I've been rewriting lately and I have following problem. Inside inner for loop, when this condition findCell(queue[0].x + i, queue[0].y + j).hasBeenSearched == true is being checked, values of second parameter queue[0].y and j are concatenated instead of just being added, while same condition for first parameter works correctly (values there are added). I'm trying to figure that out for several hours now and I have no idea what is going on. Both values queue[0].y and j are numbers(I checked it by console logging typeof them), and should be added just like similiar values in first paremeter. Any help with pointing me out what I did wrong will be appreciated. Thank you in advance.
Codepen link: http://codepen.io/Furmanus/pen/LkXVwO/?editors=0011

JS expressions are evaluated left-to-right. By the time it reaches that last +, it's evaluating ('6 1' + 5).
Put the last part in parentheses to force it to be evaluated separately: console.log(z.x+5 + ' ' + (z.y+5)).
You can also log multiple things using parentheses, which will avoid this problem: console.log(z.x+5, z.y+5).

Actually, the arguments of the findCell() function are always Numbers.
The only place where there is a string is:
console.log(queue[0].x + i + ' ' + queue[0].y + j)
This prints a string because sum is calculated from left to right.
Let's do it step by step:
queue[0].x + i are two numbers, and they are summed, and they oroduces a number (let's call it xi
So now our operation is:
console.log(xi + ' ' + queue[0].y + j)
xi is a Number, and it is summed to ' ' which is a string. They produce a string (this is how JS does casting)
From here on, you sum strings and numbers, so first of all queue[0].y is casted to string and it is concatenated, then j is casted to string too and concatenated in the same way.
Solution is to force the precedence of operators:
console.log(queue[0].x + i + ' ' + (queue[0].y + j))
TL;DR: the code is good, just the console.log is broken

When you concatenate the two values, the second one is converted to a string.
Instead, use:
var z = {x: 1, y: 1};
console.log(z.x+5 + ' ' + parseInt(z.y+5));
jsfiddle

Related

Why does my forloop run through my if statment only once?

I'm writing a calculator in JS and currently I'm writing the '=' function, now I pasted my code below, so I made exp = 5 + 5, everything works fine it tells me that total is 10, now when I do 5+5+5 it still says 10, it's as if the loop ins't working, because I want it to do 5+5 first, update the total to be 10 and then find the + operator again and then add whatever is after the plus, how do I do this? I have no idea why the loop isn't working
All help is appreciated,
Have a nice day,
larwa
function equal(){
var exp = document.form.textview.value;
var expArray = exp.split(/\b/);
console.log(expArray);
let total = 0;
for (let i = 0 ; i < expArray.length; i++){
console.log(expArray[0])
total = parseFloat(expArray[0])
if(i = '+' || '-' || '/' || '*'){
console.log(i);
n = expArray.indexOf(i)
total += parseFloat(expArray[n + 1]);
}
}
There are certain mistakes in your code.
The total should be initialized outside the for loop, otherwise it will generate incorrect total value.
if(i = '+' || '-' || '/' || '*'){, in this instead of using assignment operator i:e =, comparison operator i:e == or === (strict equality operator) should be used. As well separate comparison expressions are required i:e i=== '+' || i=== '-' || i=== '/' || i=== '*'. The i is nothing but index of the array elements, instead of i it should be array element. i:e expArray[i].
let exp = "5 + 5 + 5";
function equal() {
var expArray = exp.split(/\b/);
let total = parseFloat(expArray[0]);
for (let i = 0; i < expArray.length; i++) {
const dig = expArray[i].trim();
if (dig === '+' || dig === '-' || dig === '/' || dig === '*') {
total += parseFloat(expArray[i + 1]);
}
}
return total;
}
console.log(equal());
Try this
for (let i = 0 ; i < expArray.length; i++){
console.log(expArray[0])
total = parseFloat(expArray[0])
if(i == '+' || '-' || '/' || '*'){
console.log(i);
n = expArray.indexOf(i)
total += parseFloat(expArray[n + 1]);
}
The = operator is used for assigning values to a variable, however the == operator is used for comparison between two variables irrespective of the datatype of variable

Counting the occurrence of chars in a javascript string

I have written down code to calculate the count of each of the character in a string.
It seems to be working correctly for some of the words where as for some it fails.
It fails for the last character, as I see the length of the string becomes smaller than the iteration count (but for some of the words)
var str1 = "america"
function noofchars(str1) {
for (var m = 0; m < str1.length + 1; m++) {
var countno = 1;
if (m != 0) {
str1 = str1.slice(1)
}
str2 = str1.substr(0, 1)
for (var i = 0; i < str1.length; i++) {
if (str2 === str1.charAt(i + 1)) {
countno += 1
str1 = str1.slice(0, i + 1) + str1.slice(i + 2) + " "
}
}
console.log(str1.charAt(0) + "=" + countno)
}
}
var findnoofchar = noofchars(str1)
It passes for london, philadelphia, sears, happy
But fails for america, chicago etc
london = l=1, o=2, n=2, d=1
It'd be easier to use an object. First reduce into character counts, then iterate through the key/value pairs and console.log:
function noofchars(str1) {
let r = [...str1].reduce((a, c) => (a[c] = (a[c] || 0) + 1, a), {});
Object.entries(r).forEach(([k, v]) => console.log(`${k}=${v}`));
}
noofchars("america");
ES5 syntax:
function noofchars(str1) {
var r = str1.split("").reduce(function(a, c) {
a[c] = (a[c] || 0) + 1;
return a;
}, {});
Object.keys(r).forEach(function(k) {
console.log(k + "=" + r[k]);
});
}
noofchars("america");
It's easier to understand what reduce is doing in the above snippet.
First, we take a function with two parameters a and c. These can be called anything, I just use a and c for the accumulator and the current item.
Now, the second line:
a[c] = (a[c] || 0) + 1;
This is kind hard, so let's break it down. First let's look at what's in the parentheses:
a[c] || 0
This checks if a has a key/value pair with the key c (as in, the value of c, not the key literally being c). If that doesn't exist, it returns 0. So if a[c] exists, save it as the value of the expression, otherwise use 0.
Now, we add 1, to increment the value.
Finally, we assign the result to a[c]. So if a contained c, the value of a[c] would be incremented. If a didn't contain c, the value of a[c] would be 1.
Then, we return a to be used in the next iteration of reduce.
In the next line:
}, {});
We assign a default value for a. If we didn't do this, the first time reduce ran, a would be "a", and c would be "m" (the first two characters of america). This way, a is {} (an empty object), and c is "a". If we didn't have this second argument, our function wouldn't work.
In this line:
Object.keys(r).forEach(function(k) {...});
We're getting an array of all the keys in r, and looping through them with forEach, with k being the key.
Then, we're logging k (the key), then an equals sign =, then the value of r[k].
You can split the string by each character and then count the number of occurrence of each character by reduce function as below
function noofchars(str1) {
const chArray = str1.split('');
return chArray.reduce(function(acc, ch) {
if (acc[ch]) {
acc[ch]++;
} else {
acc[ch] = 1;
}
return acc;
}, {});
}
var str1 = "america";
var findnoofchar = noofchars(str1);
console.log(findnoofchar);
In your solution you are mutating str1 in this line
str1 = str1.slice(0, i + 1) + str1.slice(i + 2) + " "
which actually changes the length of the string and also checking str1.length in the first loop. In you case you can take the length in the first place. Working version of your code snippet is here
var str1 = "america"
function noofchars(str1) {
const len = str1.length;
for (var m = 0; m < len; m++) {
var countno = 1;
if (m !== 0) {
str1 = str1.slice(1)
}
if (str1.charAt(0) === ' ') {
break;
}
str2 = str1.substr(0, 1)
for (var i = 0; i < str1.length; i++) {
if (str2 === str1.charAt(i + 1)) {
countno += 1
str1 = str1.slice(0, i + 1) + str1.slice(i + 2) + " "
}
}
console.log(str1.charAt(0) + "=" + countno)
}
}
var findnoofchar = noofchars(str1)
Not really knowing what you are trying to accomplish with your code, one solution is to utilize the charAt and Set functions. CharAt is a more direct way to iterate over the string and the Set function eliminates duplicate characters from the set automatically.
var str1 = "america";
function noofchars(str1) {
var charList = new Set();
for (var m = 0; m < str1.length; m++) {
var charX = str1.charAt(m).substr(0, 1);
var countno = 1;
for (var i = 0; i < str1.length; i++) {
if (str1.slice(0, i + 1) == charX) {
countno++;
}
charList.add(charX + "=" + countno);
}
}
// you may need to expand set on Chrome console
console.log(charList);
// a hack to display more easily display on your screen
var listOnScreen = Array.from(charList);
document.getElementById('displaySet').innerHTML=listOnScreen;
}
noofchars(str1);
<div id="displaySet"></div>

variable input becoming nullified and breaking .charAt[]

https://jsfiddle.net/2L4t9saq/180/ is my fiddle
most of the code is just useless, ill just post the stuff that matters
var baseConverter = function(r, e, n) {
var o = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (e <= 0 || e > o.length || n <= 0 || n > o.length) return console.log("Base unallowed"), null;
var l, t = 0;
if (10 != e) {
var a = r.length;
for (l = 0; l < a; l++) {
var u, f = -1;
for (u = 0; u < o.length; u++)
if (r[l] == o[u]) {
f = 1;
break
}
if (u >= e) return console.log("Symbol unallowed in baseform"), null;
if (-1 == f) return console.log("Symbol not found"), null;
var s = a - l - 1;
t += 0 == s ? u : u * Math.pow(e, s)
}
} else t = parseInt(r);
if (10 != n) {
for (var g = []; t > 0;) {
var i = t % n;
if (i < 0 || i >= o.length) return console.log("Out of bounds error"), null;
g.push(o[i]), t = parseInt(t / n)
}
return g.reverse().toString().replace(/,/g, "")
}
return t.toString()
}
var b36torgba = function(input) {
for (var i = 1; i < (input.length / 8) + 1; i++) {
var arr = input
var r = arr.charAt[0 + (i - 1) * 8] + "" + arr.charAt[1 + (i - 1) * 8]
var g = arr.charAt[2 + (i - 1) * 8] + "" + arr.charAt[3 + (i - 1) * 8]
console.log(g.charAt[2])
var b = arr.charAt[4 + (i - 1) * 8] + "" + arr.charAt[5 + (i - 1) * 8]
console.log(b)
var a = arr.charAt[6 + (i - 1) * 8] + "" + arr.charAt[7 + (i - 1) * 8]
console.log(a)
var rrgba = baseConverter(r, 36, 10)
var grgba = baseConverter(r, 36, 10)
var brgba = baseConverter(r, 36, 10)
var argba = baseConverter(r, 36, 10)
var bigMessOfAVariable = "rgba(" + rrgba + "," + grgba + "," + brgba + "," + argba + "),"
return bigMessOfAVariable;
}
}
you can ignore the top function, all it is is a base converter script, that takes in three inputs, an input, the base its in, and the base it should be converted to: eg baseConverter(73,36,10) will output 255.
now, the problem is with my b36torgba function.
it will take in a string, which is guaranteed to have a length that is either 0, 8, or a multiple of 8, this is just standardization to make sure everything runs smoothly, without having 700 indexOf[] functions.
it takes in the input, and divides it by 8, this tells the function how many bytes it has to go through, and how many it will spit out, so a string "[7300002S7300002S]" should (divided by 8) output 2, therefore the script runs 2 iterations.
currently, it should be taking in the string, and assigning each group of 2 characters (again standard) to a specific variable, this will allow it to all be put in the end and outputted as the same string but in base 10 rgba (hence 73 being use, 73 in base 36 is 255), but before it can do any of that, it breaks when it tries to find the characters in a string, saying this syntax error:
Uncaught TypeError: Cannot read property '0' of undefined
at b36torgba ((index):40)
at window.onload ((index):55)
why does it break as soon as it tries to feed the string into my charAt()'s?
ps: i do understand that the code in its current state, if it worked, it'd only output the rgba value of the last 8 characters
Easy mistake. You're using charAt (which is a function) by doing charAt[index] (using square brackets), rather than charAt(index) (using round brackets). Fixing that up should solve your issue.
Also - you're calling the function by doing b36torgba(["7300002S7300002S"]) in your JSFiddle, and trying to do string manipulation on it. Since ["7300002S7300002S"] is an array, not a string, .charAt() won't work on it. Try calling the function by doing b36torgba("7300002S7300002S") instead.

Javascript Math.random() and conditional expressions

I would like to share with you my thoughts about this code:
for (var i = 1, max = 5; i < max; i++) {
let random = Math.random();
let expression = (random < 1 / (i + 1));
if (expression){
console.log('random is: ' + random + ' and the expression is: ' + expression + ', i is: ' + i);
}else{
console.log('random was: ' + random + ' and the expression was: ' + expression + ', i was: ' + i);
}
}
I was studying this example taken from GitHub: https://github.com/chuckha/ColorFlood
And I had trouble trying to know what was the meaning of the expression inside the if().
I used the JS repl: https://jscomplete.com/repl/
The context of this example is that this function would take a random index from 0 to 5, to map a random color to a Node.
Here we have a sample output from the repl:
"random was: 0.7118559117992413 and the expression was: false, i was: 1"
"random was: 0.478919411809795 and the expression was: false, i was: 2"
"random was: 0.4610390397998597 and the expression was: false, i was: 3"
"random was: 0.7051121468181564 and the expression was: false, i was: 4"
The syntax:
let expression = (random < 1 / (i + 1));
Means:
(i + 1) first add 1 to var i
Next, 1 / (i + 1) divide 1 by the sum (i + 1)
Let say result = 1 / (i + 1)
random < result, if the random value less than above division result than return true, else false.
So, something simple like:
for (var i = 1, max = 5; i < max; i++) {
let random = Math.random();
let expression = (random < 1 / (i + 1));
console.log(
i,
random.toFixed(2),
(1 / (i + 1)).toFixed(2),
expression
)
}
I first thought that it would be evaluated random < 1 so then as random uses Math.random() which gets a number between 0 and 1, excluding the one; I thought that part of the expression would be alway true.
But in fact after putting it into the repl I discovered that the 1 / (i+1) part is done first, and then it is done all together: random / result.
I have also read:
https://www.w3schools.com/js/js_comparisons.asp
https://www.w3schools.com/js/js_arithmetic.asp
https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Math/random
Please note that in the original post I simplified the code, the original code is:
var randomIndexFromCollection = function randomIndexFromCollection(collection) {
var index = 0;
for (var i = 1, max = collection.length; i < max; i++) {
if (Math.random() < 1 / (i + 1)) {
index = i;
debugger;
}
}
return index;
};

javascript "less than" if statement failing

Here is my function:
function reCalculate(i) {
document.getElementById("Q" + i).value = document.getElementById("C" + i).value - document.getElementById("QA" + i).value;
if (document.getElementById("Q" + i).value < 0) {
document.getElementById("Q" + i).value = 0;
}
if (document.getElementById("Q" + i).value < document.getElementById("E" + i).value && document.getElementById("Q" + i).value != 0) {
alert(document.getElementById("Q" + i).value + " is less than " + document.getElementById("E" + i).value + "?");
document.getElementById("Q" + i).value = document.getElementById("E" + i).value;
}
document.getElementById("Q" + i).value = Math.ceil(document.getElementById("Q" + i).value);
}
It checks Q, if it's less than 0, it makes it 0. Then, if it's not 0, but it's less than E, it makes it E. For some reason this function works UNLESS Q is a double digit number.
For example, if Q is 7 and E is 2, then it will leave Q at 7. However, if Q is 10 and E is 2, for some reason it thinks that 10<2, and it changes Q to 2!
Am I missing something here??
When you pull the .value of an element it returns a string. '10'<'2' will return true.
You can simply do a parseInt/parseFloat on the value, ala
var q = parseInt(document.getElementById("Q"+i).value,10)
Thats because it is considering your Q as a string while comparing.
Try the following instead:
function reCalculate(i){
var Z = document.getElementById, P = parseInt;
var qElem = Z("Q"+i);
var q = P(qElem.value, 10);
var c = P(Z("C"+i).value, 10);
var qa = P(Z("QA"+i).value, 10);
var e = P(Z("E"+i).value, 10);
q = c - qa;
if (q < 0) qElem.value = 0;
if (q < e && q != 0){
alert(q+" is less than "+e+"?");
qElem.value = e;
}
qElem.value = Math.ceil(q);
}
May be you should do a
parseFloat(document.getElementById("Q"+i).value)
to make sure you are comparing numbers
You are comparing strings not numbers. Use the unary + to convert to a number:
if (+document.getElementById("Q" + i).value < +document.getElementById("E" + i).value ...)
You should use variables by the way:
var input_one = document.getElementById("Q" + i).value,
input_two = document.getElementById("E" + i).value;
if (+input_one < +input_two) {
}

Categories

Resources