Combine Objects and place into array - JavaScript / React - javascript

I have multiple objects in an array. They each have a labelId assigned to them. If the label id is the same then I need to combine the objects by placing some of the values inside an array of the new combined object.
[
{
field: "legalName",
isOpened: false,
label: "Legal Name",
labelId: 1,
value: "John Doe"
},
{
field: "homeAddress1",
isOpened: false,
label: "Home Address",
labelId: 2,
value: "2343 Main Street"
},
{
field: "homeAddress2",
isOpened: false,
label: "Home Address",
labelId: 2,
value: "New York, NY"
}
]
What I want it to look like
[
{
isOpened: false,
label: "Legal Name",
labelId: 1,
values:
[
{field: "legalName", value: "John Doe"}
]
},
{
isOpened: false,
label: "Home Address",
labelId: 2,
values:
[
{field: "homeAddress1", value: "2343 Main Street"},
{field: "homeAddress2", value: "New York, NY"}
]
}
]
I am removing the field and value from the original object and placing it into an array of values for all objects regardless if they have the same labelId.
Code so far -
personalInfoArray.forEach(info => {
personalInfoArray.forEach(info2 => {
if ((info.labelId === info2.labelId) && (info.field !== info2.field)) {
info.values = [
{field: info.field, value: info.value},
{field: info2.field, value: info2.value}
]
}
})
})
I am looping through the same array twice in order to determine if the object has the same labelId, if success - create array. The issue is I'm not removing the properties and the other object still exists. Along with if they don't have the same labelId, nothing happens.
Thanks

This is an approach using the function Array.prototype.reduce to group the object by labelId and the function Object.values to extract the grouped objects.
let arr = [{ field: "legalName", isOpened: false, label: "Legal Name", labelId: 1, value: "John Doe" }, { field: "homeAddress1", isOpened: false, label: "Home Address", labelId: 2, value: "2343 Main Street" }, { field: "homeAddress2", isOpened: false, label: "Home Address", labelId: 2, value: "New York, NY" }],
result = Object.values(arr.reduce((a, {labelId, field, isOpened, label, value}) => {
(a[labelId] || (a[labelId] = {isOpened, label, labelId, values: []})).values.push({field, value});
return a;
}, Object.create(null)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

How to add new data items to an existing JavaScript object

I am trying to add new items to an existing JavaScript object as shown below. But both methods throw errors. I could create two separate objects by hard-coding with these values, but want to avoid it.
var defaultAmountTypeData = [
{ text: "Dollar", value: "D" },
{ text: "Percent", value: "P" },
{ text: "Sale", value: "S" },
];
var updatedAmountTypeData = [
{ text: "Dollar", value: "D" },
{ text: "Percent", value: "P" },
{ text: "Sale", value: "S" },
{ text: "New Amount", value: "NA" },
{ text: "New Percent", value: "NP" },
];
Tried the following:
Solution 1:
var updatedAmountTypeData = [
defaultAmountTypeData,
{ text: "New Amount", value: "NA" },
{ text: "New Percent", value: "NP" },
];
Solution 2:
var updatedAmountTypeData = getUpdatedAmountTypeData(){
var newobj = Object.assign(defaultAmountTypeData, {
text: "New Amount",
value: "NA",
});
newobj = Object.assign(newobj, { text: "New Percent", value: "NP" });
return newobj;
}
Use ellipsis to combine arrays.
var updatedAmountTypeData =
[
...defaultAmountTypeData,
{ text: "New Amount", value: "NA" },
{ text: "New Percent", value: "NP" }
];

Filtering array from object nested in array react

I have an array of object which objects have array, and my problem is to filter objects based on values from a nested array.
const skus = [{
id: 1,
features: ["Slim"],
fields: [{
label: "Material",
value: "Material1"
}, ]
},
{
id: 2,
features: ["Cotton"],
fields: [{
label: "Material",
value: "Material2"
}, ]
},
{
id: 3,
features: ["Slim"],
fields: [{
label: "Material",
value: "Material3"
}, ]
}
];
output should be array based on features array, example:
const result = [{
id: 2,
features: ["Cotton"],
fields: [{
label: "Material",
value: "Material2"
},
{
label: "Type",
value: "Type2"
}
]
}]
I tried to using filter method, but it only works on on objects, but not on arrays nested in objects
const filteredData = skus.filter((item) =>
(item.fields.filter((field) => field.value === "Material2")).length !== 0
);
console.log(filteredData);
I think this is what you meant...
Well to understand better you must understand that Array is also a special object only in javascript so you can perform filter on objects or the nested objects too.
skus.filter((item,keys)=>{
return item['features'].includes("Cotton") // Pass the search term in includes
})
With this you can achieve your goal.
Let me know if this works for you.
I got the same output of the example you gave using :
skus.filter(sku => sku.features.includes("Cotton"));
I hope you can explain a bit more.
The Filter method allows you to delve deeper into an objects properties and perform comparisons.
const skus = [
{ id: 1, features: ["Slim"], fields: [{ label: "Material", value: "Material1" },] },
{ id: 2, features: ["Cotton"], fields: [{ label: "Material", value: "Material2" },] },
{ id: 3, features: ["Slim"], fields: [{ label: "Material", value: "Material3" },] }
];
let featureName = "Cotton"
let results = skus.filter(s => s.features.includes(featureName))
console.log(results);
I'm unsure where "{ label: "Type", value: "Type2" }" suddenly comes from in your results though?
I write this code, and got same output,
I using id and value from index features
const skus = [
{
id: 1,
features: ['Slim'],
fields: [
{
label: 'Material',
value: 'Material1'
}
]
},
{
id: 2,
features: ['Cotton'],
fields: [
{
label: 'Material',
value: 'Material2'
}
]
},
{
id: 3,
features: ['Slim'],
fields: [
{
label: 'Material',
value: 'Material3'
}
]
}
]
const result = skus.filter(
(item) => item.id === 2 && item.features[0] === 'Cotton'
)
console.log(result)

How to filter nested arrays by searching

I have an array of objects that I want to filter by comparing a nested property to a search term.
For example:
let array = [
{
category: 15,
label: "Components",
value: "a614741f-7d4b-4b33-91b7-89a0ef96a099",
children: [
{
category: 1,
label: "Carousel1",
diId: 55946,
// as you can see there are many children nested array of object
children: [{ label: "nodatafoundmessage", value: "47d18fb2-3e63-4542-ad0e-e5e09acb5016", children: [] }],
value: "be5e027b-9163-4cfb-8816-0c8e3b816086"
},
{
category: 2,
label: "Checkbox1",
diId: 193909,
children: [{ label: "datafound", value: "47d18sb2-3e63-4542-ad0e-e5e09acb5016", children: [] }],
value: "045e8786-2165-4e1e-a839-99b1b0ceef57"
}
]
},
{
value: "4be22726-850c-4905-ab3b-039fcf607d55",
label: "Default",
children: [
{
category: 5,
defaultValueType: 1,
label: "Empty",
toType: "String",
value: "ebedb43f-4c53-491f-8954-d030321845cd"
},
{
category: 5,
defaultValueType: 2,
label: "Space",
toType: "String",
value: "2d0e1429-572b-4f21-9f83-3340bafff95a"
},
{
category: 5,
defaultValueType: 8,
label: "Current Username",
toType: "String",
value: "25f6b40a-33c7-4f17-b29d-99e8d1e4e33c"
},
{
category: 5,
defaultValueType: 9,
label: "Current Location",
toType: "Location",
value: "ed59da2f-318d-4599-9085-4d9d769a27d7"
}
]
},
{
category: 4,
label: "Fixed Value",
isFixed: true,
value: "28e90e3e-a20b-4499-9593-061a7d1e7bd6"
// as you can see there is no children in this object
}
]};
What I'm trying to achieve is if I search for 'nodata' for example my result should be
let array = [
{
category: 15,
label: "Components",
value: "a614741f-7d4b-4b33-91b7-89a0ef96a099",
children: [
{
category: 1,
label: "Carousel1",
diId: 55946,
// as you can see there are many children nested array of object
children: [{ label: "nodatafoundmessage", value: "47d18fb2-3e63-4542-ad0e-e5e09acb5016", children: [] }],
value: "be5e027b-9163-4cfb-8816-0c8e3b816086"
}
]
}
];
Another option if I search for 'spa' my result should be
let array = [
{
value: "4be22726-850c-4905-ab3b-039fcf607d55",
label: "Default",
children: [
{
category: 5,
defaultValueType: 2,
label: "Space",
toType: "String",
value: "2d0e1429-572b-4f21-9f83-3340bafff95a"
}
]
}
];
I have been super confused and I decided to get some help. Thank you for your helps guys!
The following function should do the trick for you:
function searchData(dataArray, searchTerm) {
return dataArray.flatMap(obj => {
const objHasSearchTerm = Object.entries(obj)
.some(([key, value]) => key !== 'children' && String(value).toLowerCase().includes(searchTerm.toLowerCase()));
if (objHasSearchTerm && !obj.children) return [obj];
const matchedChildren = searchData(obj.children ?? [], searchTerm);
return objHasSearchTerm || matchedChildren.length > 0
? [{
...obj,
children: matchedChildren,
}]
: [];
})
}
It recursively goes through the data array, looks for any entries that have the specified search term, and if so, places it into the newly constructed object. It will preserve the nested shape of the object, which may or may not be what is needed. Feel free to tweak the algorithm to your own needs.
let allData = [
{
category: 15,
label: "Components",
value: "a614741f-7d4b-4b33-91b7-89a0ef96a099",
children: [
{
category: 1,
label: "Carousel1",
diId: 55946,
// as you can see there are many children nested array of object
children: [{ label: "nodatafoundmessage", value: "47d18fb2-3e63-4542-ad0e-e5e09acb5016", children: [] }],
value: "be5e027b-9163-4cfb-8816-0c8e3b816086"
},
{
category: 2,
label: "Checkbox1",
diId: 193909,
children: [{ label: "datafound", value: "47d18sb2-3e63-4542-ad0e-e5e09acb5016", children: [] }],
value: "045e8786-2165-4e1e-a839-99b1b0ceef57"
}
]
},
{
value: "4be22726-850c-4905-ab3b-039fcf607d55",
label: "Default",
children: [
{
category: 5,
defaultValueType: 1,
label: "Empty",
toType: "String",
value: "ebedb43f-4c53-491f-8954-d030321845cd"
},
{
category: 5,
defaultValueType: 2,
label: "Space",
toType: "String",
value: "2d0e1429-572b-4f21-9f83-3340bafff95a"
},
{
category: 5,
defaultValueType: 8,
label: "Current Username",
toType: "String",
value: "25f6b40a-33c7-4f17-b29d-99e8d1e4e33c"
},
{
category: 5,
defaultValueType: 9,
label: "Current Location",
toType: "Location",
value: "ed59da2f-318d-4599-9085-4d9d769a27d7"
}
]
},
{
category: 4,
label: "Fixed Value",
isFixed: true,
value: "28e90e3e-a20b-4499-9593-061a7d1e7bd6"
// as you can see there is no children in this object
}
];
function searchData(dataArray, searchTerm) {
return dataArray.flatMap(obj => {
const objHasSearchTerm = Object.entries(obj)
.some(([key, value]) => key !== 'children' && String(value).toLowerCase().includes(searchTerm.toLowerCase()));
if (objHasSearchTerm && !obj.children) return [obj];
const matchedChildren = searchData(obj.children ?? [], searchTerm);
return objHasSearchTerm || matchedChildren.length > 0
? [{
...obj,
children: matchedChildren,
}]
: [];
})
}
console.log('----- Search: nodata')
console.log(JSON.stringify(searchData(allData, 'nodata'), null, 2))
console.log('----- Search: spa')
console.log(JSON.stringify(searchData(allData, 'spa'), null, 2))

Filter array of objects from nested array and nested array of objects

I have the following array of object
const skus = [
{
id: 1,
features: ["Slim"],
fields: [
{ label: "Material", value: "Material1" },
{ label: "Type", value: "Type1" }
]
},
{
id: 2,
features: ["Cotton"],
fields: [
{ label: "Material", value: "Material2" },
{ label: "Type", value: "Type2" }
]
},
{
id: 3,
features: ["Slim"],
fields: [
{ label: "Material", value: "Material3" },
{ label: "Type", value: "Type1" }
]
}
]
And i want the expected output to be
const output = [
{ label: "features", value: ["Slim", "Cotton"] },
{ label: "Material", value: ["Material1", "Material2", "Material3"] },
{ label: "Type", value: ["Type1", "Type2"] }
]
I tried the following way
const output = [];
let featureArr = [];
let fieldsArr = []
skus.forEach(e => {
e.features.forEach(f => {
featureArr.push(f);
});
e.fields.forEach(f => {
fieldsArr.push({ label: f.label, value: f.value });
});
});
featureArr = _.uniq(featureArr);
fieldsArr = _.uniqBy(fieldsArr, 'value')
fieldsArr = _.groupBy(fieldsArr, 'label');
output.push({ label: 'Features', value: featureArr })
for (const k in fieldsArr) {
let valArr = []
valArr = fieldsArr[k].map(v => v.value)
output.push({ label: k, value: valArr });
}
I'm getting the expected output, but here multiple loops are present. Is there a way on how can i write the solution in more optimized way.
You could take a grouping function for nested properties, where a map, an array for iterating, group and value keys are handed over. The result is a map with all collected values for each group.
Later get all unique values from the map and build a new array of objects.
const
skus = [{ id: 1, features: ["Slim"], fields: [{ label: "Material", value: "Material1" }, { label: "Type", value: "Type1" }] }, { id: 2, features: ["Cotton"], fields: [{ label: "Material", value: "Material2" }, { label: "Type", value: "Type2" }] }, { id: 3, features: ["Slim"], fields: [{ label: "Material", value: "Material3" }, { label: "Type", value: "Type1" }] }],
getGrouped = (map, array, key, value) => array.reduce((m, o) =>
m.set(o[key], [...(m.get(o[key]) || []), o[value]]), map),
result = Array.from(
skus.reduce((m, o) =>
getGrouped(
m.set('features', [...(m.get('features') || []), ...o.features]),
o.fields,
'label',
'value'
),
new Map
),
([label, value]) => ({ label, value: [...new Set(value)] })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
First Build an object with values as Sets. Then convert the object of sets into array of array.
const skus = [
{
id: 1,
features: ["Slim"],
fields: [
{ label: "Material", value: "Material1" },
{ label: "Type", value: "Type1" }
]
},
{
id: 2,
features: ["Cotton"],
fields: [
{ label: "Material", value: "Material2" },
{ label: "Type", value: "Type2" }
]
},
{
id: 3,
features: ["Slim"],
fields: [
{ label: "Material", value: "Material3" },
{ label: "Type", value: "Type1" }
]
}
];
const update = data => {
const res = {};
data.forEach(item => {
const features = res["features"] || new Set();
item.features.forEach(fea => features.add(fea));
res["features"] = features;
item.fields.forEach(field => {
const labels = res[field.label] || new Set();
labels.add(field.value);
res[field.label] = labels;
});
});
return Object.keys(res).map(key => ({ label: key, value: [...res[key]] }));
};
console.log(update(skus));
If you can use them, Sets will be your friend here:
//data
const skus = [{id: 1,features: ["Slim"],fields: [{ label: "Material", value: "Material1" },{ label: "Type", value: "Type1" }]},{id: 2,features: ["Cotton"],fields: [{ label: "Material", value: "Material2" },{ label: "Type", value: "Type2" }]},{id: 3,features: ["Slim"],fields: [{ label: "Material", value: "Material3" },{ label: "Type", value: "Type1" }]}];
//solution
const output = Object.entries(skus.reduce((map,sku) => {
sku.features.forEach(feat => map.features.add(feat));
sku.fields.forEach(field => (map[field.label] = (map[field.label] || new Set()).add(field.value)));
return map;
}, {features: new Set()})).map(([label, set]) => ({label, value: Array.from(set)}));
//display
console.log(output);
Each feature array and field array only get iterated exactly once using this approach.
If you can't use Sets, you can emulate their behavior using js objects. The goal is to use some structure that doesn't need to be iterated again to find unique values.
The following function will do the job
const fn = (array) => {
return array.reduce((result, element) => {
const features = result[0].value
const feature = element.features[0]
if (!features.includes(feature)) {
features.push(feature)
}
const materials = result[1].value
const material = element.fields[0].value
if (!materials.includes(material)) {
materials.push(material)
}
const types = result[2].value
const type = element.fields[1].value
if (!types.includes(type)) {
types.push(type)
}
return result
}, [
{ label: 'features', value: [] },
{ label: 'Material', value: [] },
{ label: 'Type', value: [] }
])
}
BUT, your object structure is quite messy, you should likely build accessor functions that extract information from your initial elements, and use some helper functions to populate your result object.
Anyway, read more about the 'reduce' function used here ;)
https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/reduce

Compare values ​between two object arrays

I have the following scenario:
var arr1 = [{
sys_id: "b717af1adbd0bf00daba4410ba961913",
className: "x_rdbsa_cross_fert_cross_fertilization",
display_field: {display_value: "L190322025", label: "Number", type: "string", value: "L190322025"},
secondary_fields: {display_value: "Waiting for Approval", label: "Status", type: "integer", value: "10"}];
var arr2 = [{approver: null, number: "L190322025-1", country: "Argentina", id: "0567a35adbd0bf00daba4410ba9619d6", state: "Waiting for Approval"}
I want to buy the arr2 number with the arr1 number display_field.display_value
There's an error in your example (see below) so fix that first:
var arr1 = [{
sys_id: "b717af1adbd0bf00daba4410ba961913",
className: "x_rdbsa_cross_fert_cross_fertilization",
display_field: {
display_value: "L190322025",
label: "Number",
type: "string",
value: "L190322025"
},
secondary_fields: {
display_value: "Waiting for Approval",
label: "Status",
type: "integer",
value: "10"
}
}]; // <----you forgot this closing curly brace
var arr2 = [{
approver: null,
number: "L190322025-1",
country: "Argentina",
id: "0567a35adbd0bf00daba4410ba9619d6",
state: "Waiting for Approval"
}]
// Now compare the relevant properties of first object in each array
console.log(arr1[0].display_field.display_value === arr2[0].number) // false

Categories