The value returned from the callback passed to forEach will not be used anywhere.
If you want to avoid mutating the original object and update questions, you can use Array.prototype.map and object spread syntax.
const object = {
"id": "a8df1653-238a-4f23-fe42-345c5d928b34",
"webSections": {
"id": "x58654a9-283b-4fa6-8466-3f7534783f8",
"sections": [
{
"id": "92d7e428-4a5b-4f7e-bc7d-b761ca018922",
"title": "Websites",
"questions": [
{
id: 'dee6e3a6-f207-f3db-921e-32a0b745557',
...
const updatedObject = {
...object,
webSections: {
...object.webSections,
sections: object.webSections.sections.map((section, index) => ({...section, questions: newMenu[index]}))
}
}
If you just want to mutate the original object
object.webSections.sections.forEach((_, index) => {
section.questions = newMenu[index]
})
Answer from Ramesh Reddy on Stack OverflowThe value returned from the callback passed to forEach will not be used anywhere.
If you want to avoid mutating the original object and update questions, you can use Array.prototype.map and object spread syntax.
const object = {
"id": "a8df1653-238a-4f23-fe42-345c5d928b34",
"webSections": {
"id": "x58654a9-283b-4fa6-8466-3f7534783f8",
"sections": [
{
"id": "92d7e428-4a5b-4f7e-bc7d-b761ca018922",
"title": "Websites",
"questions": [
{
id: 'dee6e3a6-f207-f3db-921e-32a0b745557',
...
const updatedObject = {
...object,
webSections: {
...object.webSections,
sections: object.webSections.sections.map((section, index) => ({...section, questions: newMenu[index]}))
}
}
If you just want to mutate the original object
object.webSections.sections.forEach((_, index) => {
section.questions = newMenu[index]
})
const newSections = myObj.webSections.sections.map((obj, index) => {
const newQuestions = newItems[index];
return {
...obj,
questions: [newQuestions],
};
});
console.log(newSections);
MyObj is the main object. This shall produce the new sections array you can combine it with your main object I suppose...
@Ramesh Reddy has the most thorough answer.
You can use a nested map() to return a modified attributes array in the object.
let fruits = [{
name: 'apple',
attributes: [{
type: 'Granny Smith',
color: 'green',
isFavorite: true
},
{
type: 'Ambrosia',
color: 'red',
isFavorite: true
}
],
isFavorite: true
},
{
name: 'Pear',
attributes: [{
type: 'Asian',
color: 'brown',
isFavorite: true
},
{
type: 'White Pear',
color: 'white',
isFavorite: false
}
],
isFavorite: true
},
]
const fruitChecked = fruits.map(fruit => ({ ...fruit,
isFavorite: true,
attributes: fruit.attributes.map(attribute => ({ ...attribute,
isFavorite: true
}))
}))
console.log(fruitChecked);
const mappedFruits = fruits.map(fruit => {
return {
...fruit,
isFavorite: true,
attributes: attributes.map(attribute => {
return {
...attribute,
isFavorite: true,
}
})
}
})
How to replace the particular value in array object of nested object with another array object in javascript - Stack Overflow
javascript - How to change the values of a nested array to all same string? - Stack Overflow
javascript - Replacing all elements in a nested Array - Stack Overflow
javascript - How to change a value of an object in an array of nested objects - Stack Overflow
A little bit late to the party, heh. I needed to modify deeply nested objects too, and found no acceptable tool for that purpose. Then I've made this and pushed it to npm.
https://www.npmjs.com/package/find-and
This small lib can help with modifying nested objects in a lodash manner. E.g.,
var findAnd = require("find-and");
const obj_res =[{
"id": "trans",
"in": "bank",
"out": "bank",
"value": 10
},{
"id": "fund",
"in": "bank",
"out": "bank",
"value": 10
}];
findAnd.changeProps(obj_res, { id: 'fund' }, { in: 'credit' });
outputs exactly what you want.
https://runkit.com/arfeo/find-and
Hope this could help someone else.
Use find() to get first instance if you think there is only one. Otherwise use filter() and loop over each to modify properties on each matching object
var obj_res = [{
"id": "trans",
"in": "bank",
"out": "bank",
"value": 10
}, {
"id": "fund",
"in": "bank",
"out": "bank",
"value": 10
}]
var fund = obj_res.find(({id}) => id === 'fund'); // returns array element or false
if (fund) {
fund.in = 'XXXXX';
console.log(obj_res)
}
Inside the forEach, you are not really modifying the array. You are passing a value to forEach, corresponding to the values of the nested array. So when you change element's variable value, you are just changing it inside the forEach callback.
There are a few ways to do this... you can go something like this.
let array = [
['A', '*', 'C'],
['A', 'B', 'C']
]
for (let nestedArray of array) {
if (nestedArray.includes('*')) {
for (let i = 0; i < nestedArray.length; i++) nestedArray[i] = '*';
}
}
console.log(array);
Run code snippetEdit code snippet Hide Results Copy to answer Expand
Or go by using splice if they all have the same fixed size (or even reassign the nestedArray to a ['*', '*', '*']).
Just to be clear: If you have this array:
['a', 'b', 'c']
And iterate it with forEach:
array.forEach(element => ...)
element will have the values 'a', 'b', 'c'. But those are NOT the same 'a', 'b', 'c' of the array. They are copies. So reassigning element to another value, won't affect the original array.
This is my solution, a function that iterates through the array and find the nested array which contains * and then replace its values
var grid = [
['A', '*', 'B'],
['C', 'D', 'E'],
['H', 'G', 'F']
]
function changeArr(grid) {
grid.forEach(arr => {
if (arr.includes('*')) {
for (var i = 0; i < arr.length; i++) {
arr.splice(i, i, '*');
}
}
})
}
console.log(grid);
changeArr(grid);
console.log(grid);
Run code snippetEdit code snippet Hide Results Copy to answer Expand
You used the wrong variable for the row index
myNumbers[column]
//needs to be
myNumbers[row]
Also your if condition is using the wrong row index, and trying to compare against the whole array instead of the value in the array
if(myNumbers[column]%2===0)
//needs to be
if(myNumbers[row][column]%2===0)
Demo
var myNumbers = [
[243, 12, 23, 12, 45, 45, 78, 66, 223, 3],
[34, 2, 1, 553, 23, 4, 66, 23, 4, 55],
[67, 56, 45, 553, 44, 55, 5, 428, 452, 3],
[12, 31, 55, 445, 79, 44, 674, 224, 4, 21],
[4, 2, 3, 52, 13, 51, 44, 1, 67, 5],
[5, 65, 4, 5, 5, 6, 5, 43, 23, 4424],
[74, 532, 6, 7, 35, 17, 89, 43, 43, 66],
[53, 6, 89, 10, 23, 52, 111, 44, 109, 80],
[67, 6, 53, 537, 2, 168, 16, 2, 1, 8],
[76, 7, 9, 6, 3, 73, 77, 100, 56, 100]
];
for (var row = 0; row < myNumbers.length; row++) {
for (var column = 0; column < myNumbers[row].length; column++) {
if (myNumbers[row][column] % 2 === 0) {
myNumbers[row].splice(column, 1, "even");
} else {
myNumbers[row].splice(column, 1, "odd");
}
}
}
console.log(myNumbers);
Probably easier to use a nested map instead:
var myNumbers = [
[243, 12, 23, 12, 45, 45, 78, 66, 223, 3],
[34, 2, 1, 553, 23, 4, 66, 23, 4, 55],
[67, 56, 45, 553, 44, 55, 5, 428, 452, 3],
[12, 31, 55, 445, 79, 44, 674, 224, 4, 21],
[4, 2, 3, 52, 13, 51, 44, 1, 67, 5],
[5, 65, 4, 5, 5, 6, 5, 43, 23, 4424],
[74, 532, 6, 7, 35, 17, 89, 43, 43, 66],
[53, 6, 89, 10, 23, 52, 111, 44, 109, 80],
[67, 6, 53, 537, 2, 168, 16, 2, 1, 8],
[76, 7, 9, 6, 3, 73, 77, 100, 56, 100]
];
const output = myNumbers.map(row => row.map(num =>
num % 2 === 0
? 'even'
: 'odd'
));
console.log(output);
Achieving the same thing with a for loop is much more verbose and confusing, and shouldn't be done in most cases (array methods have better abstraction and don't require manual iteration), but if necessary:
var myNumbers = [
[243, 12, 23, 12, 45, 45, 78, 66, 223, 3],
[34, 2, 1, 553, 23, 4, 66, 23, 4, 55],
[67, 56, 45, 553, 44, 55, 5, 428, 452, 3],
[12, 31, 55, 445, 79, 44, 674, 224, 4, 21],
[4, 2, 3, 52, 13, 51, 44, 1, 67, 5],
[5, 65, 4, 5, 5, 6, 5, 43, 23, 4424],
[74, 532, 6, 7, 35, 17, 89, 43, 43, 66],
[53, 6, 89, 10, 23, 52, 111, 44, 109, 80],
[67, 6, 53, 537, 2, 168, 16, 2, 1, 8],
[76, 7, 9, 6, 3, 73, 77, 100, 56, 100]
];
const output = [];
for (let rowIndex = 0; rowIndex < myNumbers.length; rowIndex++) {
const row = myNumbers[rowIndex];
const newRow = [];
for (let colIndex = 0; colIndex < row.length; colIndex++) {
const num = row[colIndex];
newRow.push(num % 2 === 0 ? 'even' : 'odd');
}
output.push(newRow);
}
console.log(output);
reformat your data. it will be the best way moving forward.
const array = [
{
car: 'ford',
colour: 'red',
food: {
veg: 'beans',
fruit: 'plum',
},
}
];
this way you can access the data like you want to food.fruit etc.
You'll need a recursive function that loops over each item in an array. If it encounters an object it will change on of its values if needed or call the function itself again
const array = [
{
things: [
{ car: 'ford' },
{ colour: 'red' },
{
food: [
{ veg: 'beans' },
{ fruit: 'plum' },
],
},
],
},
{},
{},
];
const changePlum = (arr, changeTo = 'strawberry') => (
arr.map(a => {
for (let k in a) {
if (Array.isArray(a[k])) {
a[k] = changePlum(a[k], changeTo);
} else if(a[k] === 'plum') {
a[k] = changeTo;
}
}
return a;
})
)
const res = changePlum(array);
console.log(res);
This is supposed to be straightforward and I was sure I knew how to do it, but it's not working for some reason. So I have a nested array and I need to convert the values of each nested array to a different value. In my function these are the indices corresponding to values from a different array, but for simplicity's sake let's say I wanna convert them all to 0. So I tried nested loops
let arr = [[ 1, 0, 2 ], [3, 1, 5]]
for (let indices of arr) {
for (let i of indices) {
i = 0
}
}
console.log(arr)And the map method
let arr = [[ 1, 0, 2 ], [3, 1, 5]]
function test(arg) {
for (let x of arg) {
x.map(e => e = 0)
}
return arg
}
console.log(test(arr))What am I missing? The array isn't being changed. I've been solving a problem since this morning so my brain is fried, this is the last step, any help is appreciated.
child property represents only one, but this alternative loops the whole array.
You can use recursion to go deeper and updated the found objects by id.
This approach mutates the original array
const allItems = [{ 'id': 1, 'text': 'old', 'child': [ { 'id': 2, 'text': 'old' } ]}],
newItems = [ { 'id': 1, 'text': 'new', 'more_info': 'abcd' }, { 'id': 2, 'text': 'new', 'more_info': 'abcd' }]
looper = (arr, items) => {
arr.forEach(outer => {
let found = items.find(n => outer.id === n.id);
if (found) {
Object.assign(outer, found);
if (outer.child) looper(outer.child, items);
}
});
};
looper(allItems, newItems);
console.log(allItems);
.as-console-wrapper { max-height: 100% !important; top: 0; }
The following will give you some hints on how to approach this problem, without providing the final answer.
Two Approaches
There are two approaches you can take to solve this problem:
Implement a
findItemById(id)method that recursively traverses throughallItemsto find an item with a specificid. Then you can call that function for each entry innewItemsand override the relevant properties if you find it.Implement a
traverseItems(itemTree, callback)method that recursively traverses each level of the item tree, and then callscallbackwith each item and child item it comes across. The callback would then check if that item's ID matches one innewItemsand if so, overwrites it's properties with those from the entry innewItems.
Commonalities
If you think about these two approaches, it becomes obvious that the thing needed in both approaches is a recursive traversal function that can go down through all the levels of allItems. So focus on getting that basic algorithm right, and then you can decide between the two. (Hint: one of them is likely to be more efficient than the other, but for small data sets, it really won't matter).
» npm install nested-replace
You could iterate the array and replace the value inside.
var array = [{ _id: "ExxTDXJSwvRbLdtpg", content: [{ content: "First paragraph", language: "en", timestamp: 1483978498 }, { content: "Erster Abschnitt", language: "de", timestamp: 1483978498 }] }];
array.forEach(a => a.content = a.content.find(c => c.language === 'en').content);
console.log(array);
Version with check for content
var array = [{ _id: "ExxTDXJSwvRbLdtpg", content: [{ content: "First paragraph", language: "en", timestamp: 1483978498 }, { content: "Erster Abschnitt", language: "de", timestamp: 1483978498 }] }, { _id: "no_content" }, { _id: "no_english_translation", content: [{ content: "Premier lot", language: "fr", timestamp: 1483978498 }, { content: "Erster Abschnitt", language: "de", timestamp: 1483978498 }] }];
array.forEach(function (a) {
var language;
if (Array.isArray(a.content)) {
language = a.content.find(c => c.language === 'en');
if (language) {
a.content = language.content;
} else {
delete a.content;
}
}
});
console.log(array);
Given that _id and language are input variables, then you could use this aggregate command to get the expected result:
db.collection.aggregate([{
$match: {
_id: _id,
}
}, {
$unwind: '$content'
}, {
$match: {
'content.language': language,
}
}, {
$project: {
_id: 1,
content: '$content.content'
}
}])
Update the getAllKeys method with:
function getAllKeys(o) {
Object.keys(o).forEach(function(k) {
contains_object = Array.isArray(o[k]) && o[k].some(val=> { return typeof val == "object" && !Array.isArray(val); });
if ((Array.isArray(o[k]) && !contains_object) || typeof o[k] !== 'object') {
keys[k] = o;
} else {
return getAllKeys(o[k]);
}
keys[k] = o;
});
}
Note: !(o[k] instanceof Array) - http://jsfiddle.net/08pnu7rx/1/
The problem is that typeof also returns object for arrays.
You want to change your function to still assign the key when the object is an array.
function getAllKeys(o) {
Object.keys(o).forEach(function(k) {
if (Array.isArray(o[k]) || typeof o[k] !== 'object') {
keys[k] = o;
} else {
return getAllKeys(o[k]);
}
});
}
Notice I swapped around the logic, so you first check for either an array or another non-object type. If that check passes, you assign the value. If not, you recurse.
You should note that this is not at all specific to arrays. You will have similar problems if you have a nested property that is a Date, for example.