Nested for loop functioning - javascript

I have trouble understanding nested for loops
posts: [
{
title: 'lorem',
comments: [
{
content: 'lorem'
user: 'John'
},
...
]
},
...
]
My goal here is to get all the comments from a specific user, in all the posts.
Here is how I proceed (I'm using mongoose, I get the user from an auth middleware)
const postsList = await Post.find();
var userComments = [];
for (var i = 0; i < postsList.length; i++) {
if (postsList[i].comments.length > 0) {
for (var j = 0; j < postsList[i].comments[j].length; i++)
if (postsList[i].comments[j].user == req.user.id) {
userComments.push(comments[j]);
}
}
}
When I try this, I get a Cannot read property 'length' of undefined. I think my error is in the second for loop, but I can't get why. Any help please?

Mark Meyer in the comments is correct.
comments is an array inside of each post object. comments[j] would refer to an element inside the comments array. comments[j].length doesn't make sense because in order to run your nested j for loop, which iterates over the comments array, you want the length of the comments array, not the length of one of its elements.
Here's the line that needs to be fixed:
const postsList = await Post.find();
var userComments = [];
for (var i = 0; i < postsList.length; i++) {
if (postsList[i].comments.length > 0) {
// for (var j = 0; j < postsList[i].comments[j].length; i++)
// fixed version below
for (var j = 0; j < postsList[i].comments.length; i++)
if (postsList[i].comments[j].user == req.user.id) {
userComments.push(comments[j]);
}
}
}

Related

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));

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]) })
})

Need to iterate through arrays having objects Vue

I have an array list and each list are groups of objects. I need to iterate through each group and check if an object in a list satisfies a condition.
This is what have been able to do but, doesn't iterate through each object.
for (i = 1; i <= this.portfolioDetails.length; i++) {
for (var j = 1; j < this.portfolioDetails[i].length; j++)
{
console.log(portfolioDetails[i][j]);
}
}
This is the list of array objects:
portfolioDetails:Array[3]
0:Object
ACCOUNTID:"S1001"
ACCOUNTNAME:"Bla bla bla"
ACCRUEDINTERESTALL:0
PRICE:0.69
UNITS:60.49
VALUE:41.98
product:null
1:Object
ACCOUNTID:"S1002"
ACCOUNTNAME:"blo bla blo"
ACCRUEDINTERESTALL:0
PRICE:0.69
UNITS:60.49
VALUE:41.98
product:null
2:Object
ACCOUNTID:"S1003"
ACCOUNTNAME:"blik blik blik"
ACCRUEDINTERESTALL:0
PRICE:0.69
UNITS:60.49
VALUE:41.98
product:null
This is simple JavaScript and has nothing to do with VueJS per se. The reason your iteration is not working is because you start with i = 1 while in coding you start with an index of 0. Also, you are including the last number with your comparison statement <= which is not in the array (because you start counting at 0, not at 1). On top of that, you can just print out object values by their keys. This all adds up to something like this:
for (let i = 0; i < this.portfolioDetails.length; i++) {
console.log(this.portfolioDetails[i].ACCOUNTID)
}
Your top loop iterate should look like:
for (i = 0; i < this.portfolioDetails.length; i++) { ... }
This code should work:
for (let i = 0; i < this.portfolioDetails.length; i--) {
for (let j = 0; j < this.portfolioDetails[i].length; j--)
{
// Check conditions here
if (this.portfoiloDetails[i][j].ACCOUNTID === 'S1002') {
// Actions goes here
}
}
}
Hi the given list of array objects is unclear but if you are trying to iterate over JSON data type, you can use the code below. This code dynamically discovers the properties and return the value of each property.
<script>
var portfolioDetails = { 'data': [
{ 'fname': 'joe', 'lname': 'smith', 'number': '34'} ,
{ 'fname': 'jim', 'lname': 'Hoff', 'number': '12'} ,
{ 'fname': 'jack', 'lname': 'jones', 'number': '84'}
] };
//iterate over the records
for (i = 0; i < portfolioDetails["data"].length; i++) {
var data = this.portfolioDetails["data"][i];
var propertiesCount = Object.getOwnPropertyNames(data).length;
//iterate over the properties of each record
for (var j = 0; j < propertiesCount; j++)
{
var propName = Object.getOwnPropertyNames (data)[j];
console.log(portfolioDetails["data"][i][propName]);
}
}
</script>

How to check duplicate entries while adding to javascript object dynamically?

I have this AngularJS service.
demoService.getDemoData($scope.countEP).then(function (data) {
console.log(data);
for (var i = 0; i < data.length; i++) {
$scope.allEditorPicks.push(data[i]);
}
});
In this case,allEditorPicks is an array i have defined at the top of the code as follows.
$scope.allEditorPicks = [];
Here's the problem, when I'm using this array and printing these data, the array has same items. Duplicating. So I need a way to check existing items and stop adding them in that allEditorPicks array. We need to do this inside the for loop. I tried adding another loop inside the for loop and read the allEditorPicks array and check. But that doesn't work too.
demoService.getDemoData($scope.countEP).then(function (data) {
console.log(data);
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < $scope.allEditorPicks.length; j++) {
if ($scope.allEditorPicks[j].itemName == data[i].itemName) {
console.log("Item Exists")
} else {
$scope.allEditorPicks.push(data[i]);
}
}
}
});
This is the solution I tried. My browser got freezes and stopped working when I run this code. Please give me a solution.
first, sort the array by itemName and then remove the duplicates according to the order.
data = data.sort(function(a,b){
return a.itemName - b.itemName;
});
for (var i = 0; i < data.length; i++) {
if(data[i].itemName === data[i++].itemName){
console.log("Item Exists");
}else {
$scope.allEditorPicks.push(data[i]);
}
}
Try this :
demoService.getDemoData($scope.countEP).then(function (data) {
for(let i = 0; i < data.length; i++){
let found = $scope.allEditorPicks.find(elt => {
return elt.itemName === data[i].itemName;
});
if(!found){
$scope.allEditorPicks.push(data[i]);
}
}
})

Categories

Resources