Java script loop through array of objects - javascript

I have java script array of objects read from html table like below
depId represent the row number,
branchId represent column number and val it linked with check box (vue js v-model)
3*3 table data:
permissions= [
[{depId:1,branchId:1,val:true},{depId:1,branchId:2,val:true},{depId:1,branchId:3}],
[{depId:2,branchId:1},{depId:2,branchId:2},{depId:2,branchId:3}],
[{depId:3,branchId:1},{depId:3,branchId:2},{depId:3,branchId:3,val:true}]
]
I need to send this data to axios API, but the data should be in below format
data[0][branches][0]=1
data[0][branches][1]=2
data[0][department]=1
data[1][branches][0]=3
data[1][department]=3
I tried something like this but it have problems (the data sent in wrong indexes)
let data={};
permissions.forEach((row, i) => {
row.forEach((col, j) => {
if (col["val"] === true) {
data[`data[${i}][branches][${j}]`] = col.branchId;
data[`data[${i}][department]`] = col.deptId;
}
});
});
console.log(data);
how the loop should be to send the data in correct way?
the current result is
"data[0][branches][0]": 1,
"data[0][department]": 1,
"data[0][branches][1]": 2,
"data[2][branches][2]": 3,
"data[2][department]": 3

You forgot a couple of commas in your permissions object.
The next problem is that you were trying to check for departmentId in permissions, but it's actually depId there.
The next thing is that you do not need to define and track i and j, they are conveniently provided to you in a forEach function as the second argument that is passed to the running function.
Here is a working version of what you were trying to achieve:
permissions = [
[{
depId: 1,
branchId: 1,
val: true
}, {
depId: 1,
branchId: 2,
val: true
}, {
depId: 1,
branchId: 3
}],
[{
depId: 2,
branchId: 1
}, {
depId: 2,
branchId: 2
}, {
depId: 2,
branchId: 3
}],
[{
depId: 3,
branchId: 1
}, {
depId: 3,
branchId: 2
}, {
depId: 3,
branchId: 3,
val: true
}]
]
let data = {};
let j = 0;
permissions.forEach((row) => {
let i = 0;
let departmentSeen = false;
row.forEach((col) => {
if (col["val"] === true) {
data[`data[${j}][branches][${i}]`] = col.branchId;
data[`data[${j}][department]`] = col.depId;
i++;
departmentSeen = true;
}
});
if (departmentSeen) {
j++;
}
});
console.log(data);

Related

I want to change the structure of my array

I need to modify a data which is coming from API. The data is coming in the form of array of objects.
const crosses = [
{
fatherLineId: 8,
fatherLineName: "2ART18-0008",
id: 54,
motherLineId: 5,
motherLineName: "2ART18-0005",
},
{
fatherLineId: 3
fatherLineName: "2ART18-0003",
id: 55,
motherLineId: 5,
motherLineName: "2ART18-0005",
}
]
I want my data to be restructured in the form of:
const resultantArr = [
{
enteryNumber: 1,
ParentName: "2ART18-0008"
},
{
entryNumber: 2,
ParentName: "2ART18-0005",
},
{
entryNumber: 3,
ParentName: "2ART18-0003"
},
and so on ...
];
Here the parentName property will have motherLineName values and fatherLineName values in the order.
When you get the result of the api call, loop through it and map the data toy our custom object, I can't provide a complete example based on your question but something like this:
You may also need to parse the apiresult into json using JSON.parse()
var resultantArr = [];
for(var i = 0; i < apiresult.length; i++)
{
resultantArr.push({"enteryNumber" : i + 1 , "ParentName" : apiresult[i].fatherLineName });
}
Loop over the array and push two separate objects into an output array. And keep a record of each object entryname that you increment by two at the end of each iteration.
const crosses=[{fatherLineId:8,fatherLineName:"2ART18-0008",id:54,motherLineId:5,motherLineName:"2ART18-0005"},{fatherLineId:3,fatherLineName:"2ART18-0003",id:55,motherLineId:5,motherLineName:"2ART18-0005"}];
const out = [];
let count = 1;
crosses.forEach(obj => {
const { fatherLineName, motherLineName } = obj;
out.push({
entryNumber: count,
parentName: fatherLineName
});
out.push({
entryNumber: count + 1,
parentName: motherLineName
});
count = count + 2;
});
console.log(out);
Hope it helps you... 🙂
const crosses = [
{
fatherLineId: 8,
fatherLineName: "2ART18-0008",
id: 54,
motherLineId: 5,
motherLineName: "2ART18-0005",
},
{
fatherLineId: 3,
fatherLineName: "2ART18-0003",
id: 55,
motherLineId: 5,
motherLineName: "2ART18-0005",
}
];
var result = [];
var count = 1;
crosses.forEach(cross => {
result.push({
parentName: cross.fatherLineName,
entryNumber: count++,
}),
result.push({ parentName: cross.motherLineName,
entryNumber: count++,
})
});
result

Is there a simpler way or different way I can approach this flag validation in JavaScript?

I have this validation that only seems to work sometimes and I don't know why unless there is something that I am not seeing. I want to use the flag variable for later on.
var flag = false
var productos_grupo_promocion = [ { "idgrupo": 1, "cantidad_producto": 5 }, { "idgrupo": 6, "cantidad_producto": 1 } ]
var arr = [ { "idgrupo": 1, "cantidad": 5 }, { "idgrupo": 6, "cantidad": 1 } ]
productos_grupo_promocion.forEach(function (obj){
var matched_elements = arr.filter(item => item.idgrupo == obj.idgrupo)
matched_elements.forEach(function(item){
if(parseInt(obj.cantidad_producto) == parseInt(item.cantidad)){
flag = true
}else{
flag = false
}
})
})
The current problem you have is, in case your last product has matching elements, but does not match the last matched_element, it will set the flag to false.
Assuming you want to have flag set to true as soon as you have 1 match, you should use Array.some.
If you want that everything matches, you should use Array.every but return false in case there are no matched_elements.
So I am assuming you want to exit early, and just change your logic to
var productos_grupo_promocion = [{
"idgrupo": 1,
"cantidad_producto": 5
}, {
"idgrupo": 6,
"cantidad_producto": 1
}]
var arr = [{
"idgrupo": 1,
"cantidad": 5
}, {
"idgrupo": 6,
"cantidad": 1
}]
function hasMatch(promos, tags) {
return promos.some(function(obj) {
var matched_elements = tags.filter(item => item.idgrupo == obj.idgrupo);
return matched_elements.some(function(item) {
return parseInt(obj.cantidad_producto) == parseInt(item.cantidad);
});
});
}
console.log(hasMatch(productos_grupo_promocion, arr));
As this would end, as soon as 1 match was found. Which is what I believe you want to achieve.
As I am not entirely sure if that would be enough for the future, why not change that you get all the promotion items that actually match, say in the following way?
const productos_grupo_promocion = [{
"idgrupo": 1,
"cantidad_producto": 5
}, {
"idgrupo": 6,
"cantidad_producto": 1
}, {
"idgrupo": 6,
"cantidad_producto": 5
}];
const arr = [{
"idgrupo": 1,
"cantidad": 5
}, {
"idgrupo": 6,
"cantidad": 1
}];
function getMatchingPromotions(promotions, tags) {
const promoDict = promotions.reduce((map, promo) => map.set(promo.idgrupo, (map.get(promo.idgrupo) ?? []).concat( promo )), new Map());
return tags.reduce((resultArr, tag) => {
const matches = promoDict.get(tag.idgrupo);
if (!matches) {
return resultArr;
}
return resultArr.concat(matches.filter(p => p.cantidad_producto === tag.cantidad));
}, []);
}
console.log( getMatchingPromotions(productos_grupo_promocion, arr) );
This one would first group all the promotions, and then find all matches per tag.
I'm not sure what your use case afterwards might be so maybe the second version is overthinking it, in which case the first one would fix your logic.

Nested Reduce with values in JS

Good morning, after an array.map I have an array containing the same assignments with some nested ratings:
const assignments = [
{
name: "assignmentOne",
difficultyRating: 1,
funRating: 2
},
{
name: "assignmentOne",
difficultyRating: 3,
funRating: 4
},
{
name: "assignmentOne",
difficultyRating: 5,
funRating: 1
}
]
Now I would like to get the total difficulty/fun rating, which would look like one of the following:
//Both the difficulty and fun rating in the same record
const assignmentsTotal = [
{
name: "assignmentOne",
totalDifficultyRating: 9,
totalFunRating: 7
}
]
//Difficulty and fun rating as separate records
const assignmentsDifficultyTotal = [
{
name: "assignmentOne",
totalDifficultyRating: 9
}
]
const assignmentsFunTotal = [
{
name: "assignmentOne",
totalFunRating: 7
}
]
I'm pretty confident the best way to do this is using the reduce method.
After some digging around the only thing that came close to what I want to achieve is the following article, yet I'm not able to get this to work properly. Is there a good way to do this from the starting point above, or would it be better to create separate arrays using array.map and after use the reduce method?
If you are looking for same 'name' objects in array, below should be ok:
const reducer = assignments.reduce((total, current) => {
return { name: current.name, difficultyRating : total.difficultyRating + current.difficultyRating, funRating : total.funRating + current.funRating } });
if you want to group objects by name, then look at lodash groupby function. In general, lodash is very handy in all array/obj functionalities.
const assignments = [{
name: "assignmentOne",
difficultyRating: 1,
funRating: 2
},
{
name: "assignmentOne",
difficultyRating: 3,
funRating: 4
},
{
name: "assignmentOne",
difficultyRating: 5,
funRating: 1
},
{
name: "assignmentTwo",
difficultyRating: 5,
funRating: 3
},
{
name: "assignmentTwo",
difficultyRating: 5,
funRating: 1
}
];
// if you want the totals as an array:
const assignmentsTotalArray = assignments.reduce((totalArr, item) => {
// check whether the assignment is already in the array
const assignmentIndex = totalArr.findIndex(elem => elem.name === item.name);
// if the assignment is not in the array, add it and initialize the totals
// otherwise update the totals
if (assignmentIndex === -1) {
totalArr.push({
name: item.name,
totalDifficultyRating: item.difficultyRating,
totalFunRating: item.funRating
});
} else {
totalArr[assignmentIndex].totalDifficultyRating += item.difficultyRating;
totalArr[assignmentIndex].totalFunRating += item.funRating;
}
return totalArr;
}, []);
console.log('### assignmentsTotalArray:');
console.log(assignmentsTotalArray);
// if you want the totals as an object:
const assignmentsTotalObject = assignments.reduce((totalObj, item) => {
// if the output object already contains the assignment, sum the ratings
// otherwise create a new key for the assignment and initialize the ratings
if (totalObj[item.name]) {
totalObj[item.name].totalDifficultyRating += item.difficultyRating;
totalObj[item.name].totalFunRating += item.funRating;
} else {
totalObj[item.name] = {
totalDifficultyRating: item.difficultyRating,
totalFunRating: item.funRating
};
}
return totalObj;
}, {});
console.log('### assignmentsTotalObject:')
console.log(assignmentsTotalObject);

Merge an item attribute of one array into items of another array

I have a few questions in regards to what would be the best approach to do the following:
Call two different API:
axios.get(contents);
axios.get(favorites);
Response will Look like this:
contents: [
{
id: 1,
value: someValue
},
{
id: 2,
value: someValue
}
];
favorites: [
{
id: 1,
contentId: 2
}
];
What would be the best approach to loop through each favorite and add an element to the contens array such as isFavorite: true when the contentId matches the id. It should look as follows:
contents: [
{
id: 1,
value: someValue
{,
{
id: 2,
value: someValue
isFavorite: true
{
];
What would be the best place to do this and is there any ES6 syntax that can easily do this? I currently have the two actions separate, one that gets the contents and one that gets the favorites, I could possibly merge those or combine them at the reducer.
Any suggestions?
You can use a Set to collect all contentId values from favorites and then iterate through your contents array. This has better time complexity than using some on an array because calling .has() on a Set is O(1):
let contents = [{
id: 1,
value: 'someValue1'
},
{
id: 2,
value: 'someValue2'
},
{
id: 3,
value: 'someValue'
}
];
let favorites = [{
id: 1,
contentId: 2
},
{
id: 2,
contentId: 3
}
];
let favoriteContents = new Set(favorites.map(f => f.contentId));
contents.forEach(c => {
if (favoriteContents.has(c.id)) c.isFavorite = true;
});
console.log(contents);
const newContents = contents.map((content) => {
const foundFavorite = favorites.find((favorite) => favorite.contentId === content.id)
if (foundFavorite) {
return {
...content,
isFavorite: true,
}
}
return content
});
You firstly need to have the promises from your API calls, and when both of them are complete you can then carry out the merge of the results.
const contentsApi = () => Promise.resolve([
{
id: 1,
value: 'foo'
},
{
id: 2,
value: 'bar'
}
])
const favouritesApi = () => Promise.resolve([
{
id: 1,
contentId: 2
}
])
let contents;
let favourites;
const contentsApiCall = contentsApi().then(res => {
contents = res;
})
const favouritesApiCall = favouritesApi().then(res => {
favourites = res;
})
Promise.all([contentsApiCall, favouritesApiCall]).then(() => {
const merged = contents.map(content => {
if(favourites.some(favourite => favourite.contentId === content.id)){
return {
...content,
isFavourite: true
}
} else {
return content;
}
})
console.log(merged)
// do whatever you need to do with your result, either return it if you want to chain promises, or set it in a variable, etc.
})

Looping through (possibly infinitely) repeating object structure

I have a problem I can't get my head around. If I am looking for an object with a certain ID in a possibly infinite data structure, how can I loop through it until I find the object I need and return that object?
If this is what my data looks like, how can I get the object with id === 3 ?
{
id: 0,
categories: [
{
id: 1,
categories: [
{
id: 2,
categories: [ ... ]
},
{
id: 3,
categories: [ ... ]
},
{
id: 4,
categories: [ ... ]
},
]
}
]
}
I tried the following:
findCategory = (categoryID, notesCategory) => {
if (notesCategory.id === categoryID) {
return notesCategory;
}
for (let i = 0; i < notesCategory.categories.length; i += 1) {
return findCategory(categoryID, notesCategory.categories[i]);
}
return null;
};
But that doesn't get ever get to id === 3. It checks the object with id: 2 and then returns null. It never gets to the object with id: 3.
Here is a JSbin: https://jsbin.com/roloqedeya/1/edit?js,console
Here is the case. when you go in to the first iteration of 'for' loop, because of the return call, the execution is go out from the function. you can check it by using an console.log to print the current object in the begin of your function.
try this
function find(obj, id) {
if(obj.id === id) {
console.log(obj) // just for testing. you can remove this line
return obj
} else {
for(var i = 0; i < obj.categories.length; i++) {
var res = find(obj.categories[i], id);
if(res) return res;
}
}
}
hope this will help you. thanks
You need to store the intermediate result and return only of the object is found.
function findCategory(object, id) {
var temp;
if (object.id === id) {
return object;
}
object.categories.some(o => temp = findCategory(o, id));
return temp;
}
var data = { id: 0, categories: [{ id: 1, categories: [{ id: 2, categories: [] }, { id: 3, categories: [] }, { id: 4, categories: [] }] }] }
result = findCategory(data, 3);
console.log(result);

Categories