For Loop Scoping with 2D Array - javascript

I am working on an Advent Code Challenge and have run into a hall. I solved this error before, but in this instance, I am stuck. The following code is giving me a Uncaught TypeError: Cannot read properties of undefined. in relation to switch (diagArray[i][j]).
My thought is that diagArray is out of scope. Is that true?
Please, any help is great!
const diagArray = [
[0,1,0,0,0,1,1,1,0,0,0,1],
[1,1,0,1,0,0,0,0,0,0,0,1],
[1,1,1,0,0,1,0,0,1,0,1,1]
]; // example data
for(let i = 0; i < diagArray.length; i++) {
for (let j = 0; j < diagArray.length; i++) {
let gammaRate = ''
let epsilonRate = ''
let ones = 0
let zeros = 0
let rates = []
switch (diagArray[i][j]) {
case 1:
ones++
break
case 0:
zeros++
break
default:
break
}
if (ones > zeros) {
gammaRate+=1
epsilonRate+=0
} else {
gammaRate+=0
epsilonRate+=1
}
rates.push([gammaRate, epsilonRate])
// console.log(rates)
}
}

for(let i = 0; i < diagArray.length; i++) {
for (let j = 0; j < diagArray.length; i++) {
This here has multiple problems.
The first for loop is fine, but the second one needs be bounded by the length of the inner array:
diagArray[i].length
And it's also currently incrementing the first loops counts with i++. That needs to be j++
Working example:
const diagArray = [
[0,1,0,0,0,1,1,1,0,0,0,1],
[1,1,0,1,0,0,0,0,0,0,0,1],
[1,1,1,0,0,1,0,0,1,0,1,1]
]; // example data
for (let i = 0; i < diagArray.length; i++) {
for (let j = 0; j < diagArray[i].length; j++) {
let gammaRate = ''
let epsilonRate = ''
let ones = 0
let zeros = 0
let rates = []
switch (diagArray[i][j]) {
case 1:
ones++
break
case 0:
zeros++
break
default:
break
}
if (ones > zeros) {
gammaRate+=1
epsilonRate+=0
} else {
gammaRate+=0
epsilonRate+=1
}
rates.push([gammaRate, epsilonRate])
console.log(rates)
}
}
Also it's usually not advisable to have loops like this for iterating arrays, since, as you've discovered, it's very easy to screw up the indices.
I recommend interating over the values of the arrays instead:
for (const row of diagArray) {
for (const value of row) {
const diagArray = [
[0,1,0,0,0,1,1,1,0,0,0,1],
[1,1,0,1,0,0,0,0,0,0,0,1],
[1,1,1,0,0,1,0,0,1,0,1,1]
]; // example data
for (const row of diagArray) {
for (const value of row) {
let gammaRate = ''
let epsilonRate = ''
let ones = 0
let zeros = 0
let rates = []
switch (value) {
case 1:
ones++
break
case 0:
zeros++
break
default:
break
}
if (ones > zeros) {
gammaRate+=1
epsilonRate+=0
} else {
gammaRate+=0
epsilonRate+=1
}
rates.push([gammaRate, epsilonRate])
console.log(rates)
}
}

Your second iteration was increasing the i variable instead of j while iterating to the length of diagArray instead of diagArray[i].
You can use the Console API to debug your values to find out where the issue originates from without having to guess.
const diagArray = [
[0,1,0,0,0,1,1,1,0,0,0,1],
[1,1,0,1,0,0,0,0,0,0,0,1],
[1,1,1,0,0,1,0,0,1,0,1,1]
]; // example data
for(let i = 0; i < diagArray.length; i++) {
for (let j = 0; j < diagArray[i].length; j++) {
let gammaRate = ''
let epsilonRate = ''
let ones = 0
let zeros = 0
let rates = []
console.log(`${i}:${j} = ${diagArray[i][j]}`)
switch (diagArray[i][j]) {
case 1:
ones++
break
case 0:
zeros++
break
default:
break
}
if (ones > zeros) {
gammaRate+=1
epsilonRate+=0
} else {
gammaRate+=0
epsilonRate+=1
}
rates.push([gammaRate, epsilonRate])
// console.log(rates)
}
}

It's because in the second for loop it says diagArray.length, and it should be diagArray[i].length so that you are getting the length of the second array.

You should update the second for loop expression like this.
for (let j = 0; j < diagArray[i].length; j++) {

Related

Why is my nested loop only finding one duplicate character in a string?

My apologies if this is a duplicate, I couldn't find an answer after searching for a while on Stackoverflow.
I am trying to use a nested loop to find any duplicate characters in a string.
So far, all I can manage to do is to find one duplicate the string.
For example, when I try the string "aabbcde", the function returns ['a', 'a'], whereas I was expecting ['a', 'a', 'b', 'b'].
I obviously have an error in my code, can anybody help point me towards what it could be?
const myStr = "aabbcde";
function duplicateCount(text){
const duplicates = [];
for (let i = 0; i < text.length; i++) {
for (let j = 0; j < text[i].length; j++) {
if (text[i] === text[j]) {
duplicates.push(text[i]);
}
}
}
return duplicates;
}
duplicateCount(myStr);
It should be something like this.
issues in this loop for (let j = 0; j < text[i].length; j++)
const myStr = "aabbcde";
function duplicateCount(text){
const duplicates = [];
for (let i = 0; i < text.length; i++) {
for (let j = i+1; j < text.length; j++) {
if (text[i] === text[j]) {
duplicates.push(text[i]);
}
}
}
return duplicates;
}
console.log(duplicateCount(myStr));
Using nested loop will make it very hard to do it,we can use a Object to store the appear count,and then filter the count
const myStr1 = "aabbcde";
const myStr2 = "ffeddbaa";
const duplicateCount = str => {
let map = {}
for(c of str){
map[c] = (map[c]??0) + 1
}
let result = []
for(m in map){
if(map[m] <= 1){
continue
}
result.push(...Array(map[m]).fill(m))
}
return result
}
console.log(duplicateCount(myStr1))
console.log(duplicateCount(myStr2))
You can simply achieve the result you're looking for by creating an object map of the string (meaning each key of the object will be each unique character of the string and their associated values will be the number of times each character is repeated in the string).
After you create an object map of the string, you can loop through the object and check if each value is greater than one or not. If they're you would push that item into a result array by the number of times the character is repeated. Please find my code here:
const myStr = 'aabbcde';
const duplicateCount = (str) => {
const result = [];
const obj = {};
str.split('').map((char) => {
obj[char] = obj[char] + 1 || 1;
});
for (key in obj) {
if (obj[key] > 1) {
for (let i = 0; i < obj[key]; i++) {
result.push(key);
}
}
}
return result;
};
console.log(duplicateCount(myStr));

Why is this comparison not working, using google aps scripts?

The code below is not giving me the expected result.
It's to compare rows from two ranges and, although the second range's last row equals the one from the first range, it gives me false as the result.
var entryValuesCom = sheet.getRange(7, 1, LastRowSource, 9).getValues();
var dbDataCom = dbSheet.getRange(2, 1, dbSheet.getLastRow(), 9).getValues();
var entryVlArray = new Array();
var dbArray = new Array();
for (var r = 0; r < entryValuesCom.length; r++) {
if (entryValuesCom[r][0] != '' && entryValuesCom[r][5] != 'Daily Ledger Bal') {
entryVlArray.push(entryValuesCom[r]);
}
}
for (var a = 0; a < dbDataCom.length; a++) {
if (dbDataCom[a][1] != '' && dbDataCom[a][8] == bank) {
dbArray.push(dbDataCom[a]);
}
}
var duplicate = false;
loop1:
for (var x = 0; x < entryVlArray.length; x++) {
loop2:
for (var j = 0; j < dbArray.length; j++) {
if (JSON.stringify(entryVlArray) == JSON.stringify(dbArray)) {
duplicate = true;
break loop1;
}
}
}
Here's a snapshot of how the array is coming:
I've tried it using .join(), but still...
This is for thousands of rows, so is this going to do well performance wise?
I believe your goal as follows.
You want to compare the arrays of entryVlArray and dbArray using Google Apps Script.
When the duplicated rows are existing between entryVlArray and dbArray, you want to output duplicate = true.
Modification points:
When your script is modified, at if (JSON.stringify(entryVlArray) == JSON.stringify(dbArray)) {, all 2 dimensional arrays are compared. I think that this might be the reason of your issue. From your script, I think that it is required to compare each element in the 2 dimensional array.
When above points are reflected to your script, it becomes as follows.
Modified script:
From:
var duplicate = false;
loop1:
for (var x = 0; x < entryVlArray.length; x++) {
loop2:
for (var j = 0; j < dbArray.length; j++) {
if (JSON.stringify(entryVlArray) == JSON.stringify(dbArray)) {
duplicate = true;
break loop1;
}
}
}
To:
var duplicate = false;
for (var x = 0; x < entryVlArray.length; x++) {
for (var j = 0; j < dbArray.length; j++) {
if (JSON.stringify(entryVlArray[x]) == JSON.stringify(dbArray[j])) {
duplicate = true;
break;
}
}
}
console.log(duplicate)
By this modification, when each element (1 dimensional array) in the 2 dimensional array is the same, duplicate becomes true.
Note:
As other method, when an object for searching each row value is prepared, I think that the process cost might be able to be reduced a little. In this case, the script is as follows. Please modify as follows.
From:
var duplicate = false;
loop1:
for (var x = 0; x < entryVlArray.length; x++) {
loop2:
for (var j = 0; j < dbArray.length; j++) {
if (JSON.stringify(entryVlArray) == JSON.stringify(dbArray)) {
duplicate = true;
break loop1;
}
}
}
To:
var obj = entryVlArray.reduce((o, e) => Object.assign(o, {[JSON.stringify(e)]: true}), {});
var duplicate = dbArray.some(e => obj[JSON.stringify(e)]);
References:
reduce()
some()
Added:
About your following 2nd question,
AMAZING!!!! Would there be a way of capturing these duplicates in a pop up, using reduce() and some()?
When you want to retrieve the duplicated rows, how about the following script? In this case, I thought that filter() is useful instead of some().
Modified script:
var obj = entryVlArray.reduce((o, e) => Object.assign(o, {[JSON.stringify(e)]: true}), {});
// var duplicate = dbArray.some(e => obj[JSON.stringify(e)]);
var duplicatedRows = dbArray.filter(e => obj[JSON.stringify(e)]);
console.log(duplicatedRows)
In this modified script, you can see the duplicated rows at the log.
About a pop up you expected, if you want to open a dialog including the duplicated rows, how about adding the following script after the line of var duplicatedRows = dbArray.filter(e => obj[JSON.stringify(e)]);?
Browser.msgBox(JSON.stringify(duplicatedRows));

unable to loop the object in Angular

I have a data like below
data = ["I253,J665,l2575"]
and I need the the results like
I253,
J665,
l2575
when i tried to use for in i am getting like I253,J665,l2575 and I tried for loops also but not getting the result
let data = ["I253,J665,l2575"]
for (let i = 0; i > this.data.length; i++) {
console.log(i)
}
for (let x of this.data) {
console.log(x)
}
tried converting the data in to string and then using split changed into array but then also i am getting typeof object only
below is my stack blitz url =: https://stackblitz.com/edit/angular-ivy-drf1dk?file=src/app/app.component.ts
Modify your data variable like below:
data = ["I253", "J665", "l2575"];
for(let i = 0; i < this.data.length; i++){
console.log(this.data[i]);
}
If you have data variable as data = ["I253,J665,l2575"];
Then split it first and then loop through the generated array:
const arr = data[0].split(',');
for(let i = 0; i < arr.length; i++){
console.log(arr[i] + ',');
}
You were having multiple mistakes. First one was with for condition it should be i < this.data.length not i > this.data.length. Then you need to split and loop over it with for (let j = 0; j < data[i].split(',').length; j++) so data[i].split(',')[j] will return expected value.
In case of 2nd for...of loop you were simply logging whole value. Here also you need to split inside for...of and use one more loop to log.
Alternatively you can also use flatMap and loop over it like for (let m of data.flatMap(x => x.split(','))).
Try it below. You can use this.data, but it won't work in below example so it is used as simply data.
let data = ["I253,J665,l2575"];
console.log("Using for loop");
for (let i = 0; i < data.length; i++) {
for (let j = 0; j < data[i].split(',').length; j++) {
console.log(data[i].split(',')[j]);
}
}
console.log("Using for...of loop");
for (let x of data) {
for (let y of x.split(',')) {
console.log(y);
}
}
console.log("Using flatMap");
for (let m of data.flatMap(x => x.split(','))) {
console.log(m);
}
Two ways to solve this.
Also note that your loop is wrong SHOULD NOT BE '>' and Should Be '<'
1. Your data is at array index zero so if you are to keep the data as is
let data = ["I253,J665,l2575"]
let splits = data[0].split(',')
for (let i = 0; i < splits.length; i++) {
console.log(splits[i])
}
or
let data = ["I253,J665,l2575"]
let splits = data[0].split(',')
for (let element of splits) {
console.log(element )
}
2. Fix the data string
let dataString = "I253,J665,l2575"
let splits = dataString.split(',')
for (let i = 0; i < splits.length; i++) {
console.log(splits[i])
}
or
let dataString = "I253,J665,l2575"
let splits = dataString.split(',')
for (let element of splits) {
console.log(i)
}
Clone of the example provided in question
https://stackblitz.com/edit/angular-ivy-izj7up

Assign an object to a key within another object

I recognize that this has been talked about, but none of the given answers are working. This is an async function.
const activeOrders = await Order.getActiveOrders()
const orderIds = activeOrders.map((order) => { return order.clientId })
const fullClients = await clientController.getClientsByIdArray(orderIds)
for (let j = 0; j < activeOrders.length; ++j) {
for (let i = 0; i < fullClients.length; ++i) {
if (String(activeOrders[j].clientId) === String(fullClients[i]._id)) {
activeOrders[j]['client'] = fullClients[i] // THIS IS NOT WORKING
console.log(activeOrders[j].client) // THIS CORRECTLY DISPLAYS fullClients[i]
console.log(activeOrders[j]) // THIS SHOWS THE OBJECT BUT DOES NOT
// INCLUDE activeOrders[j].client
}
}
}
console.log(activeOrders[0]) // HERE activeOrders[j].client IS MISSING (there is currently 1 item in each array)
const arr1 = [{stuff: "Some stuff", id: 6}]
const arr2 = [{otherIsh: "Sysreq", id: 6}]
for (let i = 0; i < arr1.length; ++i) {
for (let j = 0; j < arr2.length; ++j) {
if (arr1[i].id === arr2[j].id) {
arr1[i].newObj = arr2[j]
break
}
}
}
console.log(arr1[0])
I really don't get how it can be there in the first console.log, but then not exist in the next. In this snippet, I do the same thing and it works just fine.
Solved it. I didn't realize this had anything to do with Mongoose. Here is the link to the question with the correct answer. Unable to add properties to js object

How to improve the performance of 'for loop' to integrate some objects in JS

I have three for loop as below to integrate their objects.
The problem is the length of 'cars' array is 20,000.
So it should runs every 20,000 times for finding same id between company.user and cars.
But the id of cars is unique.
Can I reduce this repeat number in JS?
I want to reduce the taking time.
Thank you for reading it.
p.s. I uploaded same question adding the concrete logic inside of for loop.
for (let i = 0; i < company.length; i += 1) {
for (let j = 0; j < company[i].user.length; j += 1) {
for (let k = 0; k < cars.length; k += 1) {
if (company[i].user[j].id === cars[k].id) {
company[i].user[j] = {
...company[i].user[j],
...cars[k]
}
}
}
}
}
If there is only 1 match then use break after you found that item. Imagine you find that item at index 1 for example, then the loop would still continue and do 19998 loops. Because of the information that you know there is only 1 possible match you can break it there.
if (company[i].user[j].id === cars[k].id) {
company[i].user[j] = {
...company[i].user[j],
...cars[k]
}
break;
}
for (let i = 0, leni = company.length;; i < leni ; i += 1) {
for (let j = 0, lenj = company[i].user.length; j < lenj; j += 1) {
for (let k = 0, lenk = cars.length; k < lenk; k += 1) {
if (company[i].user[j].id === cars[k].id) {
company[i].user[j] = {
...company[i].user[j],
...cars[k]
}
break; // match only the first one, then stop searching for cars
}
}
}
}
Answer based on test results from https://jsperf.com/caching-array-length/4
Spread left in base on
https://thecodebarbarian.com/object-assign-vs-object-spread.html
this will optimize your code a little more, but ziga1337 is right, the only effective way is to sort your two objects
// company: [ { user: [ { id: '?1'
// cars: [ { id: '?2'
for (let iCompagny of compagny) {
for (let iUser of iCompagny.user) {
let fCar = cars.find(xCar.id===iUser.id)
if (fCar) Object.assign(iUser, fCar)
}
}
in case there is always a car.id unique to each user.id:
let indexCars = cars.reduce((a,c)=>{ a[c.id]=c; return a },{})
compagny.forEach(iCompagny=>{
iCompagny.user.forEach(iUser=>{ Object.assign(iUser, indexCars[iUser.id]) })
})

Categories

Resources