this.state = {
array: [1, 2, 3],
objects: [{ id: 1 }, { id: 2 }, { id: 3 }]
}
How can I change the specific value of an object or array in the state without setStating the whole array/object?
something like
this.setState({ array[2]: 5 })
this.setState({ object[0].id: 0 })
You could use a helper function to set an element at an index and return that newly updated array
const array = [1, 2, 3]
const object = [{id: 1}, {id: 2}, {id: 3}]
const setElementAtIndex = (index, value, array) => [
...array.slice(0, index),
value,
...array.slice(index + 1)
]
console.log(setElementAtIndex(0, 99, array))
console.log(setElementAtIndex(1, 99, array))
console.log(setElementAtIndex(2, 99, array))
console.log(setElementAtIndex(0, { ...object[0], id: 0 }, object))
this.setState({ array: setElementAtIndex(2, 5, array) })
this.setState({ object: setElementAtIndex(0, { ...object[0], id: 0 }, object) })
I would use map.
const state = {
array: [1,2,3],
objects: [{id: 1}, {id: 2}, {id: 3}]
}
const newArray = state.array.map((v, i) => i === 2 ? 5 : v);
const newObjects = state.objects.map((v, i) => i === 0 ? {...v, id: 0} : v);
console.log(newArray);
console.log(newObjects);
// this.setState({ ...this.state, array: newArray });
// this.setState({ ...this.state, objects: newObjects });
Related
I have an array of objects. Each object has a key quantity and value. I want to duplicate each object in the array based on its quantity. Next, I want to manipulate only one of the duplicated object in the array. But on manipulating value of 1 object, value of all duplicated objects change. Here is my code:
let arr = [
{ id: 1, quantity: 3, value: 10 },
{ id: 2, quantity: 1, value: 5 },
{ id: 2, quantity: 5, value: 5 },
];
const newArr = [];
for (const a of arr) {
if (a.quantity > 1) {
let quantity = a.quantity;
a.quantity = 1;
while (quantity--) {
newArr.push(a);
}
}
}
arr = newArr;
arr[0].value = 1;
When I changed the value of arr[0] to 1, value field of arr[1] and arr[2] also changed to 1.
I have tried copying the object using spread operator and JSON.parse(JSON.parse()), but none has worked.
Because newArr.push(a) .a push to newArr ref to element of arr
You can edit same as :
let arr = [
{ id: 1, quantity: 3, value: 10 },
{ id: 2, quantity: 1, value: 5 },
{ id: 2, quantity: 5, value: 5 },
]
const newArr = []
for (const a of arr) {
if (a.quantity > 1) {
let quantity = a.quantity;
a.quantity = 1;
while (quantity--) {
newArr.push({...a})
}
}
}
arr = [...newArr]
arr[0].value = 1
console.log(arr)
// example for Memory Management
let a = { id: 1, quantity: 3, value: 10 }
let b = { id: 1, quantity: 3, value: 10 }
let c = arr[0]
let d = {...arr[0]}
console.log(a === arr[0]) // false : different allocates memory for contain value
console.log(a === b) // false : different allocates memory for contain value
console.log(c === arr[0]) // true : refer to a memory
console.log(d === arr[0]) // false : different allocates memory for contain value
I am having array of objects where i want to reduce the array and get the count of two properties. When my array length is more than one it works but when its one or less it doesn't
const data = [{id: 1, count:3 , alt_count: 2}, {id: 2, count:4 , alt_count: 5}];
const countObj = data.reduce((acc, curr) => {
return {
count_total: acc.count + curr.count,
alt_count_total: acc.alt_count + curr.alt_count,
};
});
console.log(countObj) // giving me both count_total and alt_count_total
But here its not giving me, instead it gives me the same object
const data = [{id: 1, count:3 , alt_count: 2}];
const countObj = data.reduce((acc, curr) => {
return {
count_total: acc.count + curr.count,
alt_count_total: acc.alt_count + curr.alt_count,
};
});
console.log(countObj) // giving me entire first object
Any help is appreciated
You need to provide the initial value to reduce.
const data = [{
id: 1,
count: 3,
alt_count: 2
}];
const countObj = data.reduce((acc, curr) => {
return {
count_total: acc.count + curr.count,
alt_count_total: acc.alt_count + curr.alt_count,
};
}, {
count: 0,
alt_count: 0
});
console.log(countObj);
I have an array of objects with the following structure:
let sampleData = [
{ values: { val1: 4, val2: 5, val3: 7 } , time: "1571372233234" , sum: 16 },
{ values: { val1: 5, val2: 3, val3: 1 }, time: "1571372233234" , sum: 9},
{ time: "14354545454", sum: 0},
{ time: "14354545454", sum: 0} }
];
I need to take each key within each object inside array and form an array out of it. Basically grouping based on the key present in all the objects.If the object has no "values" it should return 0 across the val1,val2,val3 Help would be appreciated.
The resultant array of objects should look like:
result = [
{ name: 'val1', data: [4, 5, 0, 0] },
{ name: 'val2', data: [5, 3, 0, 0] },
{ name: 'val3', data: [7, 1, 0, 0] }
]
I have tried so far:
var result = sampleData.map(value => ({ value: value.values }));
You could reduce the array. Create an accumulator with each valx as key and { name: valx, data: [] } as it's value. Loop through the keys of each values and update the accumulator. Then use Object.values() to get the values of the merged object to get the desired output
const sampleData = [
{ values: { val1: 4, val2: 5, val3: 7 } },
{ values: { val1: 5, val2: 3, val3: 1 }},
{ values: { val1: 4, val2: 7, val3: 2 } },
{ values: { val1: 5, val2: 1, val3: 5 } }
];
const merged = sampleData.reduce((acc, { values }) => {
for (const name in values) {
acc[name] = acc[name] || { name, data: [] }
acc[name].data.push(values[name])
}
return acc;
}, {})
const output = Object.values(merged)
console.log(output)
Update:
If values is optional, you could check if values is undefined. But, if you need 0 when values doesn't exist, then another step is required. First, we need to get all the possible valx keys available in the array. Because, if { time: "14354545454", sum: 0} appears in the beginning of the array, there is no way of knowing what possible keys exist in the array. You can do this using flatMap and Set. Then loop through the set of keys for every object. If values doesn't exists, add a default 0 for the current valx key being looped.
let sampleData = [
{ values: { val1: 4, val2: 5, val3: 7 } , time: "1571372233234" , sum: 16 },
{ values: { val1: 5, val2: 3, val3: 1 }, time: "1571372233234" , sum: 9},
{ time: "14354545454", sum: 0},
{ time: "14354545454", sum: 0}
];
const keySet = new Set( sampleData.flatMap(a => Object.keys(a.values || {})) )
const merged = sampleData.reduce((acc, { values = {} }) => {
keySet.forEach(name => {
acc[name] = acc[name] || { name, data: [] }
acc[name].data.push(values[name] || 0)
})
return acc;
}, {})
console.log(Object.values(merged))
My JSON array
var jData = [
{id: 1, parent: null},
{id: 2, parent: null},
{id: 3, parent: 1},
{id: 4, parent: 2},
{id: 5, parent: 2},
{id: 6, parent: 1}];
I want this be to sorted like the following ( by id then by the parent )
[
{id: 1, parent: null},
{id: 3, parent: 1},
{id: 6, parent: 1}
{id: 2, parent: null},
{id: 4, parent: 2},
{id: 5, parent: 2},
];
What is the best way to do it in JavaScript?
I tried, but no luck
jData .sort((a, b) => a.id - b.id ||a.parent- b.parent);
Help!!
You need a topological sorting first and then take the nodes in order of appearance.
function getData(array) {
return array.flatMap(({ data, children = [] }) => [data, ...getData(children)]);
}
var data = [{ id: 1, parent: null }, { id: 2, parent: null }, { id: 3, parent: 1 }, { id: 4, parent: 2 }, { id: 5, parent: 2 }, { id: 6, parent: 1 }],
tree = function (data, root) {
var t = {};
data.forEach(data => {
Object.assign(t[data.id] = t[data.id] || {}, { data });
t[data.parent] = t[data.parent] || {};
t[data.parent].children = t[data.parent].children || [];
t[data.parent].children.push(t[data.id]);
});
return t[root].children;
}(data, null),
result = getData(tree);
console.log(result);
console.log(tree); // just to show what's happening
.as-console-wrapper { max-height: 100% !important; top: 0; }
If parent is null we use the id as parent value and sort by parent first (otherwise we won't reach your result). If the parent value comparison results in zero, we sort by id.
var jData = [{id:5,parent:2},{id:1,parent:null},{id:4,parent:2},{id:2,parent:null},{id:3,parent:1},{id:6,parent:1}];
let res = jData.sort((a,b) => {
let ap = a.parent ? a.parent : a.id,
bp = b.parent ? b.parent : b.id;
return ap - bp || a.id - b.id;
});
console.log(res);
You can use reduce to group each array to its parent. Use 0 if parent is null. Use another reduce to contruct the final array.
var jData = [{"id":1,"parent":null},{"id":2,"parent":null},{"id":3,"parent":1},{"id":4,"parent":2},{"id":5,"parent":2},{"id":6,"parent":1}]
var temp = jData.reduce((c, v) => {
let p = v.parent || 0;
c[p] = c[p] || [];
c[p].push(v);
return c;
}, {});
var newjData = temp[0].reduce((c, v) => {
var o = temp[v.id] || [];
o.sort((a, b) => a.id - b.id); //Sort. Incase the IDs are not in order in the original array.
c.push(v, ...o);
return c;
}, []);
console.log(newjData);
I'm trying merge arrays into one in javascript.
I have this Array:
[{ID: 111, SEG: 4}, {ID: 111, SEG:
3}]
And I need this:
[{ID: 111, SEG: [3, 4]}]
This can be approximated to a solution, depending on the data:
var items = [
{
id: 1,
value: 5
},
{
id: 1,
value: 3
},
{
id: 2,
value: 40
},
{
id: 2,
value: 35
}
];
var group = function (arr, groupBy) {
var values = {};
arr.forEach(function (element) {
var item = element;
var index = item[groupBy];
if (!values[index]) {
values[index] = item;
}
else {
item.value += values[index].value;
}
values[index] = item;
});
return Object.keys(values).map(function (k) { return values[k]; });
};
console.log(group(items, 'id'));
The Problem can be solved using reduce.
let dataJ = [{ID: 111, SEG: 4}, {ID: 111, SEG: 3}]
let newData = dataJ.reduce(function(acc, curr) {
let index = acc.findIndex(item => item.ID === curr.ID);
if (index === -1) {
acc.push(curr);
} else {
if (!acc[index].SEG || !Array.isArray(acc[index].SEG)) {
acc[index].SEG = [];
}
acc[index].SEG.push(curr.SEG);
}
return acc;
}, []);
console.log(newData); // [{ID: 111, SEG: [3, 4]}]