Initializing a variable while concatenating another one - javascript

I have this for loop with variable value_from_db
for (var i = 0; i < arrayLength; i++) {
var value_from_db = array[i].value;
}
However I need to make the variable value_from_db_0, value_from_db_1, value_from_db_2 ... depending on i.
Something like:
var value_from_db_+i = array[i].value;
The purpose is
for (var i = 0; i < arrayLength; i++) {
if( array[i].condition == '0' ) {
jQuery("#username").on('change', function() {
var value = this.value;
if( value === array[i].value ) { //because array[i].value doesnot seem to work here
count++;
alert(count);
}
}
}
because array[i].value doesnot seem to pass through the anonymous function, I am trying to differentiate the varialbe.

You have a couple of options here. The first obvious one is to use an array:
var value_from_db = array.map(item => item.value)
// then access them with the index directly
console.log(value_from_db[0])
But if you really want those variable names, you could house them within an object fairly easily:
var myObj = {}
array.forEach((item, i) => myObj[`value_from_db_${i}`] = item.value)
// the use with something like
console.log(myObj.value_from_db_0)
After reading the comments on #Igors closure answer, it looks like what you are trying to do (and this is best guess from the vague comment), is watch for changes to #username, and figure out if all the array values have been matched at one point or another. If I'm correct, you could do it like this:
// remove unwanted condition items
var conds = array.filter(item => item.condition === '0')
// watch for element changes
jQuery("#username").on('change', function() {
var comparer = this.value
// update a match key for any items where a match is found
conds
.filter(item => item.value === comparer)
.forEach(item => item.match = true)
// check if all matches have been found
if(conds.every(item => item.match)){
alert('all matched')
}
})

After edit of the question this became an entirely different issue that has to do with closure and captured variable.
Potentially repeating calls jQuery("#username").on('change', ... look suspicious, but maybe there is only one array[i].condition == '0' in the array.
for (var i = 0; i < arrayLength; i++) {
if( array[i].condition == '0' ) {
jQuery("#username").on('change', (function(aValue) {
return function() {
var value = this.value;
if (value === aValue) {
count++;
alert(count);
}
};
})(array[i].value));
}
}

Related

Why does this code only work in certain JS executors?

This code takes an integer and returns the amount of 1s that are present.
function countOnes(i) {
let str = i.toString();
let ones = 0;
for(let x = 0; x < i.length; x++) {
if(str.charAt(x) === '1') ones++;
}
return ones;
}
console.log(countOnes(111000));
But it only appears to work in certain executors of JavaScript. If I enter this code into p5.js or Mozilla MDN, I will receive the desired output of 3.
But if I use the console in my browser and some other websites emulating that, 0 will be returned with every given value.
Why is this the case?
you cant loop on i.length, i its still a 'Number' type,
you should loop on "str.length" instead.
you better give more meaningful names... i should be num,
str should be numStr, ones should be counter.
try this:
function countOnes(num) {
var counter = 0;
var numsArray = Array.from((num + ''))
numsArray.forEach(num => {
return (num == 1)? counter++ : ''
})
return counter
}
console.log(countOnes(1110010)); // 4

Difference of two 2D arrays

I am trying to make function to get me difference of two 2D arrays but I found that to make function removeArray() work it's required to take different counter variables in both function. If it's taken i in both than loop iterate only once where it should iterate twice.
function removeArray(toremove, myarray){
for(i=0; i< toremove.length ; i++){
// console.log(getIndex(toremove[i],myarray));
myarray.splice(getIndex(toremove[i],myarray),1);
console.log("" + myarray); //only [2,3] will get remove
}
}
function getIndex(array, myarray){
for(i=0;i< myarray.length ; i++){
// if(typeof(array)== 'undefined'){console.log("error"); return 100;}
if((myarray[i][0] == array[0]) && (myarray[i][1] == array[1])){
return i;
}
}
}
var myarray=[[1,1],[1,2],[1,3],[1,4],[2,1],[2,2],[2,3],[2,4],[3,1],[3,2],[3,3],[3,4],[4,1],[4,2],[4,3],[4,4]];
var toremove=[[2,3],[3,3]];
removeArray(toremove,myarray);
Also when commented parts are included(both together) i.e, // console.log(getIndex(toremove[i],myarray)) and // if(typeof(array)== 'undefined'){console.log("error"); return 100}it iterates infinitely where it should have not more than twice.
Why is it so? Pls help. Thanks in advance!
The problem is that you do not define i with var or let. In that case i is a global variable and is shared by the two functions.
So when the nested getIndex function is called, i potentially increments until myarray.length. Then when execution comes back inside the first function's loop, i is already too great to continue looping. The loop there exits and all is done.
Instead define i as a local function variable (var) or block variable (let) and it will work:
function removeArray(toremove, myarray) {
for(let i = 0; i < toremove.length; i++) {
myarray.splice(getIndex(toremove[i], myarray), 1);
}
}
function getIndex(array, myarray){
for(let i = 0; i < myarray.length; i++){
if (typeof(array)== 'undefined') {
console.log("error");
return 100;
}
if ((myarray[i][0] == array[0]) && (myarray[i][1] == array[1])) {
console.log("found match at position " + i);
return i;
}
}
}
var myarray=[[1,1],[1,2],[1,3],[1,4],[2,1],[2,2],[2,3],[2,4],[3,1],[3,2],[3,3],[3,4],[4,1],[4,2],[4,3],[4,4]];
var toremove=[[2,3],[3,3]];
console.log("before: " + JSON.stringify(myarray));
removeArray(toremove,myarray);
console.log("after: " + JSON.stringify(myarray));
Usually the better practice is to not mutate an array with splice, but to return a new copy without the items to be removed. You can use filter and every for that. And then you must assign the function's return value to the array that should have the result (could also overwrite the same array):
function removeArray(toremove, myarray){
return myarray.filter(arr =>
toremove.every(rem => arr[0] != rem[0] || arr[1] != rem[1])
);
}
var myarray=[[1,1],[1,2],[1,3],[1,4],[2,1],[2,2],[2,3],[2,4],[3,1],[3,2],[3,3],[3,4],[4,1],[4,2],[4,3],[4,4]];
var toremove=[[2,3],[3,3]];
console.log("before: " + JSON.stringify(myarray));
myarray = removeArray(toremove, myarray);
console.log("after: " + JSON.stringify(myarray));
Maybe .filter method be good for you
function removeArray(toremove, myarray) {
return myarray.filter((el) => {
for (let i in toremove) {
if (toremove[i][0] === el[0] && toremove[i][1] === el[1]) {
return false;
}
}
return true;
});
}
var myarray=[[1,1],[1,2],[1,3],[1,4],[2,1],[2,2],[2,3],[2,4],[3,1],[3,2],[3,3],[3,4],[4,1],[4,2],[4,3],[4,4]];
var toremove=[[2,3],[3,3]];
console.log(removeArray(toremove,myarray));
It is iterating once because your code is getting into an error. javascript always passes variable by reference. You can refer this to understand
Uncaught TypeError: Cannot read property '0' of undefined on line 16
you can use below logic to avoid error
function removeArray(toremove, myarray){
let indexes = []
for(i=0; i < toremove.length ; i++){
indexes.push(getIndex(toremove[i],myarray))
}
for (var i = indexes.length -1; i >= 0; i--)
myarray.splice(indexes[i],1);
}

NodeJS require with asynch functions when synch is wanted

I have the following code
var utils = require(`${__dirname}/../../utils/utils.js`);
...
let object = utils.parse(input);
if (object === undefined){
let helper = utils.recognize(input);
msg.channel.sendMessage("\"" + input + "\" not recognized. Did you mean \"" + helper[0] + "\"?");
object = utils.parse(helper[0]);
}
//code related to object
console.log(object.strLength);
where "parse" tries to match the input to an object in a database, and "recognize" tries to find the best match if the input is spelled incorrectly (Levenshtein) (along with additional info such as how close the match was).
Currently the issue is that the code is ran asynchronously; "object.strLength" returns an undefined before utils.recognize() returns a value. If I copy/paste the recognize() and parse() functions into the file, then the code is run synchronously and I do not run into any issues. However I would rather keep those functions in a separate file as I reuse them in other files.
Is there a way to specify that the functions in utils must be synch? I know that there are libraries that convert asynch into synch but I prefer to use as few libraries as I can help it. I tried to have the recognize functions return a Promise but it ended up as a jumbled mess
edit: here's parse. I did not think it was necessary to answer this question so I did not include it initially:
var db = require(`${__dirname}/../data/database.js`);
...
var parse = (input) => {
let output = db[output];
if (output === null) {
Object.keys(db).forEach((item) => {
if (db[item].num === parseInt(input) || (db[item].color + db[item].type === input)){
output = db[item];
return false;
}
});
}
return output;
}
I solved the issue, thanks everyone. Here's what was wrong, it was with recognize(). It was my mistake to not show the code for it initially.
Original recognize:
var recognize = (item) => {
//iterate through our databases and get a best fit
let bestItem = null;
let bestScore = 99999; //arbitrary large number
//let bestType = null;
//found algorithm online by milot-mirdita
var levenshtein = function(a, b) {
if (a.length == 0) { return b.length; }
if (b.length == 0) { return a.length; }
// swap to save some memory O(min(a,b)) instead of O(a)
if(a.length > b.length) {
let tmp = a;
a = b;
b = tmp;
}
let row = [];
for(let i = 0; i <= a.length; i++) {
row[i] = i;
}
for (let i = 1; i <= b.length; i++) {
let prev = i;
for (let j = 1; j <= a.length; j++) {
let val;
if (b.charAt(i-1) == a.charAt(j-1)) {
val = row[j-1]; // match
} else {
val = Math.min(row[j-1] + 1, // substitution
prev + 1, // insertion
row[j] + 1); // deletion
}
row[j - 1] = prev;
prev = val;
}
row[a.length] = prev;
}
return row[a.length];
}
//putting this here would make the code work
//console.log("hi");
Object.keys(db).forEach((key) => {
if (levenshtein(item, key) < bestScore) {
bestItem = key;
bestScore = levenshtein(item, key);
}
});
return [bestItem, bestScore];
}
My solution was to move the levenshtein function outside of the recognize function, so if I wanted to I can call levenshtein from another function
#user949300 and #Robert Moskal, I changed the forEach loop into a let...in loop. There is no functional difference (as far as I can tell) but the code does look cleaner.
#Thomas, I fixed the let output = db[output]; issue, oops.
Again, thanks for all of your help, I appreciate it. And happy New Year too

javascript for loop is not incrementing

I am trying to using a for loop for trying to validate the input of the user and this is the code i got.
function Valid() {
objfieldid = ["userMail", "userCont"]
objboxid = ["cancelMail", "cancelCont"]
return objfieldid.every(callnonvalid)
}
function callnonvalid(id) {
var valid = false
var objlength = objfieldid.length
objlength--;
for (var i = objlength; i >= 0; i--){
var cobj = document.getElementById(objboxid[i]).checked;
if (document.getElementById(id).value != "" ){
var obj = document.getElementById(id).value;
} else if (cobj == true) {
alert(i); //return 1, 1
return true
} else {
return false
}
}
}
As you can see, in the code, the for loop is running twice. but the i variable is left unchanged. Why would this happen?
btw, I did read different material about closure and i am sure there didnt got a closure problem
EDIT:guys please note that i did noticed the array is zero based, and i did minus the objlength by one.
Mistakes were found after checking the code carefully. The Mistake that I made was that I should not use the return for the out since that would stop the function from working, however that array.every Called the function twice which make the i not decreasing
I'm not sure why you're decrementing in your loop, because the performance gain would be infinitesimally small (it may even be slower, e.g. in Chrome/V8) and working in reverse order can get confusing further down the line, but that's your choice and I don't know enough about what you're doing to judge.
Either way, I don't think you'd want to decrement objlength before the loop begins as you are doing now. The whole point of a loop is to handle the incrementing/decrementing in the condition statement of the loop.
You would only decrement manually like that if you were going to move your if/else if/else statement into a closed over function and execute it recursively, decrementing the objlength from within the closure. Which would work, but it's unnecessarily complicated for what you're doing and you would gain nothing for rewriting the whole thing.
So, sticking with the looping approach, perhaps try either of these:
function Valid() {
objfieldid = ["userMail", "userCont"];
objboxid = ["cancelMail", "cancelCont"];
return objfieldid.every(callnonvalid);
}
function callnonvalid(id) {
var valid = false;
var objlength = objfieldid.length;
for(var i = 0; i < objlength; i++){
var cobj = document.getElementById(objboxid[i]).checked;
if (document.getElementById(id).value != "" ){
var obj = document.getElementById(id).value;
} else if (cobj == true) {
alert(i);
return true;
} else {
return false;
}
}
}
or, if you want to decrement, use while instead of for:
function Valid() {
objfieldid = ["userMail", "userCont"];
objboxid = ["cancelMail", "cancelCont"];
return objfieldid.every(callnonvalid);
}
function callnonvalid(id) {
var valid = false;
var i = objfieldid.length;
while(i--){
var cobj = document.getElementById(objboxid[i]).checked;
if (document.getElementById(id).value != "" ){
var obj = document.getElementById(id).value;
} else if (cobj == true) {
alert(i);
return true;
} else {
return false;
}
}
}
Because the array objboxid[] has only two elements, the first time through your loop objboxid[2] will be attempting to fetch an array index that is out-of-bounds.
You probably meant something like:
for (var i = objlength; i > 0; i--){
var cobj = document.getElementById(objboxid[i-1]).checked;
or perhaps
for (var i = objlength-1; i >= 0; i--){
var cobj = document.getElementById(objboxid[i]).checked;

Is there a way to check if several vars are all equal to each other in javascript?

I have jQuery included so if it helps to use it, it's available.
First the simple question:
Is there a way to check if several vars are all equal to each other?
I can use the transitive relation logic and do
if ((a == b) && (b == c)) && (c == d)) ... {
to avoid checking every variable against EACH other, but I think there should be a fancier way to do this.
If you can answer this first part only, it would be much appreciated.
Now, the tricky part...
I have a variable amount of variables (between 1 and 5)
I know that their value can be any of 200 possible values from a DDBB.
What would be the best way to know how many instances of each value I have within those variables?
For example...
If I have...
var1 = VALUE_A;
var2 = VALUE_A;
var3 = VALUE_B;
var4 = VALUE_Z;
var5 = VALUE_Z;
... i want to get something like:
result["VALUE_A"] => 2
result["VALUE_B"] => 1
result["VALUE_Z"] => 2
///////////////////////////
OR if i have...
var1 = VALUE_A;
var2 = VALUE_C;
var3 = VALUE_B;
... get:
result["VALUE_A"] => 1
result["VALUE_C"] => 1
result["VALUE_B"] => 1
///////////////////////////
OR if i have...
var1 = VALUE_A;
var2 = VALUE_A;
var3 = VALUE_A;
var4 = VALUE_C;
var5 = VALUE_C;
... get:
result["VALUE_A"] => 3
result["VALUE_C"] => 2
///////////////////////////
OR if i have...
var1 = VALUE_A;
var2 = VALUE_A;
var3 = VALUE_A;
... get:
result["VALUE_A"] => 3
Hope I was clear. Examples were the only way I could think of explaining clearly.
If this is too complex for Javascript or processing so many possible values up to times 5 can make the browser slow I can do it in PHP and get the result via AJAX but I'd rather not.
Would something like this do?
function countOccurrences(arr) {
var result = {};
$.each(arr, function(index, value) {
if (!result[value])
result[value] = 1;
else
result[value]++;
});
return result;
}
This function accepts an array of the values, and returns an object whose keys are the elements and values are the number of occurrences of each.
For your first question, I don't think there's any special way of doing that.
For the 2nd: I would suggest storing those variables in an array. So your code becomes :
var myVars = [];
myVars[0] = VALUE_A;
myVars[1] = VALUE_A;
myVars[2] = VALUE_B;
myVars[3] = VALUE_Z;
myVars[4] = VALUE_Z;
Then you can just simply loop through the array and count the occurrences of each value.
The short answer is no, that is not possible. JavaScript allows for local variable definitions which can't be lifted from the environment.
The long answer is more nuanced. Variables which are declared without var or variables which are declared right on the window often are accessible, but it is a headache to do that. And you can often get a variable's value through eval, but that still does not give access to the variable's name (which is what you need for all of the above).
If you have a series of known values, then you can loop through the variables:
var tests = [
VALUE_A,
VALUE_B,
VALUE_A,
VALUE_C
]
function areAllEqual( arr )
{
for( var i = 0; i < arr.length - 1; i++ )
{
if( arr[ i ] != arr[ i + 1 ] ) return false;
}
return true;
}
console.log( areAllEqual( tests ) ) // false;
console.log( areAllEqual( [1,1,1] ) ) // true;
function getOccurances(arr) {
var result = {};
for( var i = 0; i < arr.length; i++ )
{
if( isNaN( result[ arr[ i ] ] ) ) result[ arr[ i ] ] = 1;
else result[ arr[ i ] ]++;
}
return result;
}
// this is not guaranteed to be in any order.
console.log( getOccurances( tests ) ) // {VALUE_A:2, VALUE_B:1, VALUE_C:1};
Answering the first question.
This function might help if there are a lot of variables to compare.
function allEq(arr)
{
var next;
var curr = arr.pop();
while (arr.length)
{
next = arr.pop();
if (curr != next)
return false;
curr = next;
}
return true;
}
var a = 1, b = 1, c = 1, d = 1;
var myArr = [a, b, c, d];
if (allEq(myArr)) ... {
I think you need to create your own object. The object is basically a wrapper around an array of key/value pairs. Then you need a couple of methods for .isTrue() or whatever.
You said you wanted something fancier....
So why not add to the Array object your own methods and properties to get the job done.... Hopefully, it's clear enough.
KeyValuePair.prototype.value = null;
KeyValuePair.prototype.key = null;
function KeyValuePair(key, value) {
this.key = key;
this.value = value;
this.Equals = Equals;
function Equals(o) {
if (this.value == o.value)
return true;
else
return false;
}
}
Array.prototype.ValuesAreEqual = ValuesAreEqual;
Array.prototype.GetValues = GetValues;
function ValuesAreEqual() {
this.sort();
for (var i = 0; i <= this.length - 1; i++) {
var last = this.pop();
var first = this.shift();
if (first) {
return first.Equals(last);
}
}
}
function GetValues(value) {
var arr = new Array();
if (this.length > 0) {
for (var i = 0; i <= this.length - 1; i++) {
if (this[i].value) {
if (this[i].value == value) {
arr.push(this[i].value);
}
}
}
}
return arr;
}
//code below would demonstrate the functionality of the above.
var x = new Array();
x.push(new KeyValuePair("A","Hello"));
x.push(new KeyValuePair("B","Hello"));
x.push(new KeyValuePair("C","Hello"));
var y = x.GetValues("Hello");
document.writeln(y.length);
document.writeln('\r\n');
document.writeln(x.ValuesAreEqual());

Categories