React: set the state based on array values - javascript

I have an array of questions like this
[
{
title: 'what_are_your_hobbies',
},
{
title: 'do_you_know_german',
},
]
how can I iterate over this array and set its titles to the state like:
state = {
what_are_your_hobbies: '',
do_you_know_german: ''
}

You could use reduce to iterate over the array and set all title to a key on the new object and use that to update your state.
Example
const arr = [
{
title: "what_are_your_hobbies"
},
{
title: "do_you_know_german"
}
];
const stateUpdate = arr.reduce((result, element) => {
result[element.title] = "";
return result;
}, {});
this.setState(stateUpdate);

Related

How to update an array of objects with data taken from the corresponding elements of another same-size array?

Say I have an array of objects as follows:
data = [
{
"id":34
},
{
"id":35
},
{
"id":36
},
{
"id":37
}
]
and another array as follows:
myNumberArray = [1,2,3,4]
They might be much larger, but the number of elements in both arrays will always be the same. I want to modify each element of data by adding a number attribute, assigning it the value from the corresponding element of myNumberArray.
When done, data will look as follows:
data = [
{
"number":1,
"id":34
},
{
"number":2,
"id":35
},
{
"number":3,
"id":36
},
{
"number":4,
"id":37
}
]
How can I do this?
myNumberArray = [1,2,3,4]
data = [
{
"id":34
},
{
"id":35
},
{
"id":36
},
{
"id":37
}
]
data.forEach((elem, index)=>{
data[index]["number"]=myNumberArray[index];
})
console.log(data);
This should solve your problem.
Explanation:
I used forEach to iterate over the data array, forEach accepts two parameters, the current value at an index, and the value.
Since, yours is a one-to-one mapping, we are using the current index to access the value at the same index in myNumberArray and assigning that new value in data for number key.
Try the following solution:
let myNumberArray = [1,2,3,4];
let data = [
{
"id":34
},
{
"id":35
},
{
"id":36
},
{
"id":37
}
];
const updatedArray = data.map((item,index)=> {
return {
...item,
"number":myNumberArray[index]
}
});
console.log(updatedArray);
let myNumberArray = [1,2,3,4]
let data = [
{
"id":34
},
{
"id":35
},
{
"id":36
},
{
"id":37
}
]
data = data.map( (x, i) => ({ number: myNumberArray[i], id: x.id}) )
console.log(data)
for (let i in myNumberArray) {
Object.assign(data[i], {
number: myNumberArray[i]
})
}

JS: Filter() Array of Objects based on nested array in object?

The data
const data = [
{
id: 1,
title: "Product Red",
inventoryItem: {
inventoryLevels: {
edges: [{ node: { location: { name: "Warehouse Red" } } }],
},
},
},
{
id: 2,
title: "Product Blue",
inventoryItem: {
inventoryLevels: {
edges: [{ node: { location: { name: "Warehouse Blue" } } }],
},
},
},
];
let result = data.filter((product) => {
return product.inventoryItem.inventoryLevels.edges.forEach((inventoryLevel) => {
return inventoryLevel.node.location.name !== "Warehouse Blue";
});
});
console.log(result);
What I want to do is filter by location name. I am not sure how to construct filtering based on nested arrays.
So the result I want is if the location isn't Warehouse Blue. data should just have the object where location name is warehouse red.
You should get your work done using findIndex() instead of your forEach.
This method would search and return the index of your condition, if is not found it will return -1
let result = data.filter(product => product.inventoryItem.inventoryLevels.edges.findIndex(item => item.node.location.name !== "Warehouse Blue") !== -1 )
let result = data.filter((product) => {
return product?.inventoryItem?.inventoryLevels?.edges
.some(edge => edge?.node?.location?.name !== ('Warehouse Blue'))
});
Can use lodash too Lodash: how do I use filter when I have nested Object?

Filter array of objects based on criteria in another array of objects

I want to filter items from the categories array based on the criteria in the otherCategories array.
If otherCategories contains an object where title matches one title from categories.subCategory[i].title and name matches categories.subCategory[i].details.name, then filter only that object e.g "item1" from categories.
var categories = [
{
title:"item1",
subCategory:[
{
title:"subCat1",
details:{
name:"detail1",
email:"test#test.com"
}
},
{
title:"subCat2",
details:{
name:"detail2",
email:"test#test.com"
}
}
]
},
{
title:"item2",
subCategory:[
{
title:"subCat1",
details:{
name:"detail3",
email:"test#test.com"
}
},
{
title:"subCat2",
details:{
name:"detail2",
email:"test#test.com"
}
}
]
}
]
var otherCategories = [
{
title:"subCat1",
name:"detail1"
}
]
Expected result
categories = [
{
title:"item1",
subCategory:[
{
title:"subCat1",
details:{
name:"detail1",
email:"test#test.com"
}
},
{
title:"subCat2",
details:{
name:"detail2",
email:"test#test.com"
}
}
]
}]
Use Array.reduce, Array.filter & Array.some
Convert the otherCategories array to an object with title as key and name as value
Filter categories array where some subCategory exists with matching values
var categories = [{title:"item1",subCategory:[{title:"subCat1",details:{name:"detail1",email:"test#test.com"}},{title:"subCat2",details:{name:"detail2",email:"test#test.com"}}]},{title:"item2",subCategory:[{title:"subCat1",details:{name:"detail3",email:"test#test.com"}},{title:"subCat2",details:{name:"detail2",email:"test#test.com"}}]}];
var otherCategories = [{title:"subCat1",name:"detail1"}];
var obj = otherCategories.reduce((a,c) => Object.assign(a,{[c.title]:c.name}), {});
categories = categories.filter(v => v.subCategory.some(o => obj[o.title] === o.details.name));
console.log(categories);
You could map the categories to the results by filtering the subCategories:
function matches(sub, filters) {
return filters.some(filter => filter.title === sub.title && filter.name === sub.name);
}
const result = categories.map(({ title, subCategories }) => ({ title, subCategories: subCategories.filter(sub => matches(sub, otherCategories)) }));
Another approach that will usually work for simple objects like the ones in your example, is to convert your otherCategories array to an array of "stringified" objects, and then filter categories by comparing "stringified" versions of the desired subCategory key value pairs to the converted otherCategories array.
Important to note, however, that object property order is not guaranteed in JavaScript (although many browsers will preserve property order). That means that this approach may not work in some situations and an approach like the one suggested by #NikhilAggarwal is more stable.
For example:
const categories = [{title: "item1", subCategory: [{title: "subCat1", details: {name: "detail1", email: "test#test.com"}},{title: "subCat2", details: {name: "detail2", email: "test#test.com"}}]}, {title: "item2", subCategory: [{title: "subCat1", details: {name: "detail3", email: "test#test.com"}},{title: "subCat2", details: {name: "detail2", email: "test#test.com"}}]}];
const otherCategories = [{title: "subCat1", name: "detail1"}];
const matches = otherCategories.map((item) => JSON.stringify(item));
const results = categories.filter((item) => {
for (const sub of item.subCategory) {
const match = JSON.stringify({title: sub.title, name: sub.details.name});
if (matches.includes(match)) {
return true;
}
return false;
}
});
console.log(results);

Updating an array of objects without mutation

If I have an object:
[
{
"value":"d1",
"label":"bathstore.com",
"selected":true
},
{
"value":"d2",
"label":"superdrug.com",
"selected":true
},
{
"value":"d3",
"label":"papajohns.com",
"selected":true
}
]
how can I change every value of 'selected' field to 'false' using spread operator or Object.assign() to avoid object mutation?
You can iterate over array with map and inside each callback use spread syntax to create new objects with updated property:
let data = [
{
"value":"d1",
"label":"bathstore.com",
"selected":true
},
{
"value":"d2",
"label":"superdrug.com",
"selected":true
},
{
"value":"d3",
"label":"papajohns.com",
"selected":true
}
];
let newData = data.map((item) => {
return {...item, selected: false};
});
console.log(newData);

Create new array from iterating JSON objects and getting only 1 of its inner array

See jsfiddle here: https://jsfiddle.net/remenyLx/2/
I have data that contains objects that each have an array of images. I want only the first image of each object.
var data1 = [
{
id: 1,
images: [
{ name: '1a' },
{ name: '1b' }
]
},
{
id: 2,
images: [
{ name: '2a' },
{ name: '2b' }
]
},
{
id: 3
},
{
id: 4,
images: []
}
];
var filtered = [];
var b = data1.forEach((element, index, array) => {
if(element.images && element.images.length)
filtered.push(element.images[0].name);
});
console.log(filtered);
The output needs to be flat:
['1a', '2a']
How can I make this prettier?
I'm not too familiar with JS map, reduce and filter and I think those would make my code more sensible; the forEach feels unnecessary.
First you can filter out elements without proper images property and then map it to new array:
const filtered = data1
.filter(e => e.images && e.images.length)
.map(e => e.images[0].name)
To do this in one loop you can use reduce function:
const filtered = data1.reduce((r, e) => {
if (e.images && e.images.length) {
r.push(e.images[0].name)
}
return r
}, [])
You can use reduce() to return this result.
var data1 = [{
id: 1,
images: [{
name: '1a'
}, {
name: '1b'
}]
}, {
id: 2,
images: [{
name: '2a'
}, {
name: '2b'
}]
}, {
id: 3
}, {
id: 4,
images: []
}];
var result = data1.reduce(function(r, e) {
if (e.hasOwnProperty('images') && e.images.length) r.push(e.images[0].name);
return r;
}, [])
console.log(result);
All answers are creating NEW arrays before projecting the final result : (filter and map creates a new array each) so basically it's creating twice.
Another approach is only to yield expected values :
Using iterator functions
function* foo(g)
{
for (let i = 0; i < g.length; i++)
{
if (g[i]['images'] && g[i]["images"].length)
yield g[i]['images'][0]["name"];
}
}
var iterator = foo(data1) ;
var result = iterator.next();
while (!result.done)
{
console.log(result.value)
result = iterator.next();
}
This will not create any additional array and only return the expected values !
However if you must return an array , rather than to do something with the actual values , then use other solutions suggested here.
https://jsfiddle.net/remenyLx/7/

Categories

Resources