i have a simple function that takes in an array of objects and one object that has been modified. The Goal is to exchange the modified object in the old array of objects and then log the updated array of objects
my Take:
async mutateTodos(currentTodos: ITodos[], editedTodo: ITodos) {
const Index = currentTodos.findIndex((el) => el.id === editedTodo.id);
const updatedTodos = currentTodos.splice(Index, 1, editedTodo);
console.log(updatedTodos);
}
For some Reason, updatedTodos only returns an array containing the old object that was at the index that has been identified properly.
I cant wrap my head around why this doesnt work
splice mutates the array on which the method is called. The return value is not that mutated array, but the slice of the array that was removed from it. In this case it is an array with the old todo.
There are many ways to get the result you want. For instance, you could first create a copy, then call splice on it, and then return that mutated copy.
const updatedTodos = [...currentTodos];
updatedTodos.splice(Index, 1, editedTodo);
console.log(updatedTodos);
Related
how do I map these items in the component to render on the screen, I'm not sure because it's an array of objects and it contains "pacotes" which is also an array of objects, I made a filter to render only "pacotes"
useEffect(() => {
const filtrando = teste.filter((item) => (item.pacotes))
console.log(filtrando)
}, [])
filter takes a callback that outputs a truthy or falsy value. It's used to remove elements from an array that don't match. An array is truthy, so your filter won't do anything, unless one of your items doesn't have a pacotes key.
You are probably looking for .map. const filtrando = teste.map((item) => (item.pacotes)) will output an array that is only the pacotes array from the original items.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
I'd ask a better question, but I don't don't know how. Thanks for your help.
***ISSUE: I'm sending array vari to a function and it's coming back changed even though I didn't return it or even use same variable name. Desired function: variable vari does not change
I've logged the function and isolated the change to the [].forEach() statement below, noted with ***. I send vari but return varis and assign to new variable sum. How does this change the vari variable?
//this is what calls the sub function using vari, an array, 411.0, 13.0
var sum = doSum1(vari);
function doSum1(vari0) {
// called from doSum1
// grab Variance data // ALL COLUMNS FOR NOW // fix loc/stat columns below
var vstat = vari0[0].indexOf('Status');
vari1 = vari0.filter(r=>r[vstat]); // to ensure indexOf works, and speed processing
var vhdr = ['Campaign ID','Campaign','Site ID','Site','Placement','Placement ID','Date','DCM Imp','Upw Imp','Tag Location','Status','Site Count','Site Imp'];
// move loc and status over in place of variance and percent (loc/stat will be site ct/imp)
varis=[];
// *** THIS FOREACH CHANGES varis AND vari. Not sure how... see more specifically below
['Not Tracking','Undertracking','Overtracking','Absent in DCM'].forEach(rf=>{
varis.push(vhdr.map(r=>''));
varis[varis.length-1][0]=rf;
varis.push(vhdr);
if(vari1.filter(r=>r[vstat].indexOf(rf)>=0).length==0) {
varis.push(vhdr.map(r=>''));
varis[varis.length-1][0]='none found';
} else {
varis.push(vari1.filter(r=>r[vstat].toString().indexOf(rf)>=0)[0]); // break out of outer []
//fix loc/stat location
//*** MORE SPECIFICALLY, this line in particular changes in vari, not just varis as intended.
varis[varis.length-1].splice(9,4,varis[varis.length-1][11],varis[varis.length-1][12],'','')
}
varis.push(vhdr.map(r=>'')); // trailing blank line
});
return varis;
I tried this in place of the splice as well, but same result... just not sure how varis is changing vari...
varis[varis.length-1][9] = varis[varis.length-1][11];
varis[varis.length-1][10] = varis[varis.length-1][12];
varis[varis.length-1][11] = '';
varis[varis.length-1][12] = '';
vari is a 2D array. That means that every element in vari is an array as well, and as such passed by reference and subject to mutation.
The Array.splice() method mutates its argument array. In the code, each varis[varis.length-1].splice() call modifies an array object that is copied from vari1 by reference, and therefore also vari0 whose elements are array objects that are copied to vari1 by reference. This is what causes vari to mutate.
To avoid the issue, use one these patterns:
var vari1 = vari0.map(row => row.slice()).filter(r => r[vstat]);
or
var vari1 = vari0.map(row => row.map(value => value)).filter(r => r[vstat]);
The patterns use Array.map() and Array.slice()to get a shallow copy of the 2D array referenced by vari0 (i.e., vari).
The first map() creates a new array of that contains the rows of vari0. The rows are arrays and therefore mutable, so a slice() or another map() is required to copy the rows into new arrays as well.
Note that the copy is shallow, which means that only primitive values such as text strings and numbers are copied by value. Your comments indicate that the rows of vari only contain primitives, so the pattern will make a copy that is safe to modify and will not mutate vari. Were the rows of the vari 2D array contain yet more arrays or other objects, the would be copied by reference and therefore still be subject to mutation.
Note that Array.splice() and Array.slice() are very different from each other. The Array.splice() method mutates its argument array. The Array.slice() method creates a shallow copy of the array, and is in fact often used to safely copy 1D arrays that contain primitives. In your use case, the vari array does not contain primitives but arrays, so we need to call slice() within map() to copy the primitive values in the second level of the 2D array.
In the general case, deep cloning an array or another object is surprisingly complex. The patterns above are probably the simplest way to do it in your use case. See What is the most efficient way to deep clone an object in JavaScript?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
as per document says The filter() method creates a new array with all elements that pass the test implemented by the provided function.
According to document below script should console Learning console.log(Arr[0].name) // Learning
var Arr = [{name:'Learning'},{name:'Questing'}]
var Arr2 = Arr.filter(it=> true);
Arr2[0].name = 'Stack-Over-Flow';
console.log(Arr[0].name) // Stack-Over-Flow
Yes, .filter creates a new array, but the new array is the only new structure that is created. The items inside the array remain unchanged.
With your code, after filtering, you have a new array which contains 2 items, where both of those items are references to the same objects that were in the original array. So, mutating one of the objects in the new array results in the objects in the old array being mutated, because they point to the same object in memory.
If you wanted to avoid this, you'd have to deep clone the array first, perhaps with
const Arr2 = Arr
.filter(it => true)
.map(obj => ({ ...obj }));
.filter does create a new array, but the array of the filtered elements from the old array.
While the element from the old is object, so that new array still keep its reference. To avoid that, you could do a .map to clone the element for the whole new reference
var Arr = [{name:'Learning'},{name:'Questing'}]
var Arr2 = Arr.filter(it=> true).map(el => ({...el}));
Arr2[0].name = 'Stack-Over-Flow';
console.log(Arr[0].name)
So I have a 2-dimensional Array and want to use a "randomBool" function on each of the elements of the elements in the array.
The "randomBool" function just returns a random boolean:
const randomBool = () => Boolean(Math.round(Math.random()));
this would be the 2-dimensional Array, that I would input:
var test = [
["just","some","random","text"],
[1412,"test",1278391]
]
There is a working for-loop nested in a for-loop:
for (let el of test){
for(let i in el){
el[i] = randomBool();
}
}
I tried this:
test.forEach(el => el.map(el2 => randomBool()));
But it didn't work. Why?
You need to use two nested maps.
const randomBools = test.map(outer => outer.map(inner => randomBool()))
forEach is usually intended to iterate over each item in order to perform some kind of side effect without returning anything and without mutating the original array. For example, printing each item to the console.
map, on the other hand, is intended to take an array and return a new array of the same size, with the values transformed in some way, without mutating the original array. For example, uppercase all the words in a list.
Since you want to return a new 2 dimensional from your existing 2 dimension array with some data transformed, you need to nest your map functions. This will map first over the rows (outer), then the columns (inner). The results of the inner maps will be collected into the outer map and you'll be left with a 2 dimensional array with your new values, all without modifying the original array.
How can I use the data stored in the array cottageGallery from this mapped data?
const galleryData = components.map(g => {
return {
cottageGallery: g.cottageGallery,
destinationGallery: g.destinationGallery,
activitiesGallery: g.activitiesGallery,
}
})
I thought it would simply be const cottageGallery = galleryData.cottageGallery but this returns undefined.
Not quite, galleryData is going to be an array not an object as you are using javascript's map method. If you wanted to get the first item of the array you could do the following - [0] being the first item of the array.
const cottageGallery = galleryData[0].cottageGallery;
To log each cottageGallery you could use forEach and do the following:
galleryData.forEach(item => {
console.log(item.cottageGallery);
})
galleryData is an array of the objects returned by the map callback. So you'd use galleryData[index].cottageGallery, where index is in the range 0 through galleryData.length - 1 (or any of the various ways you access entries in an array, such as for-of or forEach or...more here).
map Will return an array so you won't be able to simply access galleryData.cottageGallery. You might want to use .reduce() on your array so the outcome can be the object your were trying to create
You can also use forEach to access object array like below:
galleryData.forEach(a => {
console.log(a.cottageGallery);
})