i have a array of object i need to join all into one single object as parent child
for example
let array= [
{
"Gender": "male",
"Type": "backpacks",
"Key": "size",
"Values": "small,large,medium"
},
{
"Gender": "male",
"Type": "backpacks",
"Key": "strap",
"Values": "padded,non-padded"
},
{
"Gender": "female",
"Type": "backpacks",
"Key": "pocket",
"Values": "multiple,zip,buckle"
},
{
"Gender": "female",
"Type": "backpacks",
"Key": "size",
"Values": "small,large,medium"
},
{
"Gender": "female",
"Type": "sunglasses",
"Key": "size",
"Values": "XL,XXL,XXL"
},
{
"Gender": "female",
"Type": "sunglasses",
"Key": "color",
"Values": "red,black,yellow"
},
]
expected output
let obj={
"male": {
"backpacks": {
"size": "small,large,medium",
"strap": "padded,non-padded"
},
},
"female": {
"backpacks": {
"size": "small,large,medium",
"strap": "padded,non-padded"
},
"sunglasses": {
"size": "XL,XXL,XXL",
"color": "red,black,yellow"
}
}
}
i tried created a blank object and a for loop then each iteration i added into that object but since it have more level of nest am not able to do
i tried using lodash _.flatten but now working as i expected
As you point out, since you are grouping the items at multiple depths, a lodash helper like _.groupBy won't work here, so you'll need to build the object yourself.
You can either reduce your array, or manually loop over it and build your object, whichever you find easier to understand.
I'll use an iterative approach since I'm guessing that'll be easier to understand.
function groupItems(items) {
let mainGroup = {};
for (let item of items) {
const { Gender, Type, Key, Values } = item;
// If we don't have an object to group by gender yet, create one
if (!mainGroup[Gender]) {
mainGroup[Gender] = {};
}
// If we don't have an object to group this gender's product yet, create one
if (!mainGroup[Gender][Type]) {
mainGroup[Gender][Type] = {};
}
// Finally, save the value under the (lowercased) key we received
mainGroup[Gender][Type][Key.toLowerCase()] = Values;
}
return mainGroup;
}
let array = [{"Gender":"male","Type":"backpacks","Key":"size","Values":"small,large,medium"},{"Gender":"male","Type":"backpacks","Key":"strap","Values":"padded,non-padded"},{"Gender":"female","Type":"backpacks","Key":"pocket","Values":"multiple,zip,buckle"},{"Gender":"female","Type":"backpacks","Key":"size","Values":"small,large,medium"},{"Gender":"female","Type":"sunglasses","Key":"size","Values":"XL,XXL,XXL"},{"Gender":"female","Type":"sunglasses","Key":"color","Values":"red,black,yellow"}];
console.log(groupItems(array));
Loop through the array, creating each nested object as needed, then filling in the Key: Values elements.
let array= [
{
"Gender": "male",
"Type": "backpacks",
"Key": "size",
"Values": "small,large,medium"
},
{
"Gender": "male",
"Type": "backpacks",
"Key": "strap",
"Values": "padded,non-padded"
},
{
"Gender": "female",
"Type": "backpacks",
"Key": "pocket",
"Values": "multiple,zip,buckle"
},
{
"Gender": "female",
"Type": "backpacks",
"Key": "size",
"Values": "small,large,medium"
},
{
"Gender": "female",
"Type": "sunglasses",
"Key": "size",
"Values": "XL,XXL,XXL"
},
{
"Gender": "female",
"Type": "sunglasses",
"Key": "color",
"Values": "red,black,yellow"
},
]
let obj = {};
array.forEach(({Gender, Type, Key, Values}) => {
if (!obj[Gender]) {
obj[Gender] = {};
}
if (!obj[Gender][Type]) {
obj[Gender][Type] = {};
}
obj[Gender][Type][Key] = Values;
});
console.log(obj);
Related
I am trying to change the value of object from the array but, it's not work as expected. I tried following.
const arrObj = [
{
"label": "test1",
"value": 123,
"type": "number",
"field": {
"label": "another",
"description": "abcd"
}
},
{
"label": "test2",
"value": 111,
"type": "number"
},
]
arrObj.forEach(obj => {
obj = {...obj, ...obj.field}
delete obj.field
})
console.log("after:", arrObj);
Also I found some solution that to use index but, it add index before the object.
const arrObj = [
{
"label": "test1",
"value": 123,
"type": "number",
"field": {
"label": "abcd",
"description": "abcd"
}
},
{
"label": "test2",
"value": 111,
"type": "number"
}
]
arrObj.forEach((obj, index) => {
obj[index] = {...obj, ...obj.field}
delete obj.field
})
console.log("after:", arrObj);
How can I do with forEach?
Edit:
I want to remove the field object and assign/overwrite all the property outside.
Using map and assigning the result is probably a better way of doing this, but if you want to use forEach, you need to assign to the original array inside the loop:
const arrObj = [
{
"label": "test1",
"value": 123,
"type": "number",
"field": {
"label": "another",
"description": "abcd"
}
},
{
"label": "test2",
"value": 111,
"type": "number"
},
]
arrObj.forEach(({ field, ...rest}, idx, orig) => {
orig[idx] = { ...rest, ...field }
})
console.log(arrObj);
I would use map to change an array, but you may have a reason that you wish to modify the original. You could just reassign arrObj to the output of the map.
const arrObj = [
{
"label": "test1",
"value": 123,
"type": "number",
"field": {
"label": "another",
"description": "abcd"
}
},
{
"label": "test2",
"value": 111,
"type": "number"
},
]
const newArr = arrObj.map(( obj ) => {
const {field, ...rest} = obj
return {...field, ...rest}
})
console.log("after:", newArr);
I am working on an angular application. I have an array as follows:
[{
"Name": "Andy"
},
{
"Name": "Bayer"
},
{
"Name": "James"
},
{
"Name": "Doda"
}]
I have another array which containes data as follows:
[
{
"Name": "Andy",
"Id": "1",
"Time": "2020-06-19T11:02+00:00"
},
{
"Name": "Billy",
"Id": "2",
"Time": "2020-06-19T11:05+00:00"
},
{
"Name": "Ciena",
"Id": 5
"Time": "2020-06-19T11:05+00:00"
},
{
"Name": "Doda",
"Id": "4",
"Time": "2020-06-19T11:05+00:00"
}
]
I want a resultant array such that code should check if Name is present in first array, then it should copy data from second array for that Name and push it in resultant array. For example common name between above two array is Andy and Doda, so data from Andy and Doda should be pushed to resultant array as follows:
[{
"Name": "Andy",
"Id": "1",
"Time": "2020-06-19T11:02+00:00"
},
{
"Name": "Bayer"
},
{
"Name": "James"
},
{
"Name": "Doda",
"Id": "4",
"Time": "2020-06-19T11:05+00:00"
}]
At run time I may get many names so code should be generic. I was trying following code which I got over stackoverflow itself
this.newArray = _.map(this.resultantArray, item => {
const value = _.find(this.dataArray, ['Name', item]);
const obj = value ? value : {Name: item};
return obj;
});
But this code is not working as expected as it works fine for the first time but when data comes for second time it appends data to previous data. I want array to be populated again freshly every time I send data. Please help
You can do this with vanilla JS no need for lodash. You can first map it and inside that you can find the value from second array otherwise return the current object:
var arrayTwo = [ { "Name": "Andy", "Id": "1", "Time": "2020-06-19T11:02+00:00" }, { "Name": "Billy", "Id": "2", "Time": "2020-06-19T11:05+00:00" }, { "Name": "Ciena", "Id": "5", "Time": "2020-06-19T11:05+00:00" }, { "Name": "Doda", "Id": "4", "Time": "2020-06-19T11:05+00:00" } ];
var arrayOne = [{ "Name": "Andy"}, { "Name": "Bayer"}, { "Name": "James"}, { "Name": "Doda"}];
var result = arrayOne.map(val=>arrayTwo.find(p=>p.Name==val.Name) || val);
console.log(result);
Suppose first array name is First
First : any [] = [{"Name": "Andy"},{"Name": "Bayer"},{ "Name": "James"},{"Name": "Doda"}]
And Second array name is Second
Second : any[] = [{"Name": "Andy","Id": "1","Time": "2020-06-19T11:02+00:00"},{"Name": "Bayer"},{"Name": "James"},{"Name": "Doda","Id": "4","Time": "2020-06-19T11:05+00:00"}]
Now do looping and check each name of first if its exists in second copy from second and push in result array
result : any[] =[];
this.First.forEach((element) => {
let index = this.Second.findIndex((x) => element.Name== x.Name);
if (index > -1) {
let data = {
this.Second[index].Name,
this.Second[index].Id,
this.Second[index].time,
};
this.result.push(data);
}
}
I want to push into array of objects keys and values dynamically. I thought that was pretty simple, something like:
list.forEach(element => {
element["carAttributes"].map((o) =>
{
this.car.push(
{
o.Name: o.Value
}
);
})
});
but it's not working because { o: any; } is not assignable to type CarInterface where CarInterface is:
export interface CarInterface {
"name": string;
}
o returns me something like
{"Name": "name", "Value": "Mercedes"}
what I have to do is take the value of the key Name and the value of the key Value and put everything in one object like:
{"name": "Mercedes"}
I have many values so i have to push everything in this.car list. Is that possible?
EDIT:
It could be something like that
{
"Cars": [{
"carAttributes": [{
"Name": "name",
"Value": "Mercedes"
}, {
"Name": "color",
"Value": "grey"
}, {
"Name": "model",
"Value": "A220"
}],
"available": true,
},{
"carAttributes": [{
"Name": "name",
"Value": "Mercedes"
}, {
"Name": "color",
"Value": "red"
}, {
"Name": "model",
"Value": "B250E"
}],
"available": false,
}]
}
I need to create an array of objects for each car that has this kind of structure
[
{"name": "Mercedes", "color": "grey", "model": "A220"},
{"name": "Mercedes", "color": "red", "model": "B250E"},
]
That's it.
I am trying to filter out a nested array of objects using lodash which is pretty straightforward but I am looking to avoid multiple calls.
I am looking to create 2 array of objects using a single lodash call/function. Looking to find object property "$isMultiAccount" if it exists put the whole object into one result set and if not put it to another ruleset.
Currently I am doing this with Lodash "has and filter" for first and for other "!has" which means same object is looped twice , as object is relatively large its creating bottleneck for speed
https://repl.it/repls/HomelyExpensiveTruetype
const item = {
"domains": [
{
"id": "dm11022",
"information":{
"description": "Customer",
"owner": {
"primary":{
"name": "James",
"phone": "NA"
},
"others": [
{
"$isMultiAccount": "./Yes"
}
]
}
}
},
{
"id": "dm12022",
"information":{
"description": "Customer",
"owner": {
"primary":{
"name": "James",
"phone": "NA"
},
"others": [
{
"$isMultiAccount": "./No"
}
]
}
}
},
{
"id": "dm12022",
"information":{
"description": "Customer",
"owner": {
"primary":{
"name": "James",
"phone": "NA"
},
"others": [
{
"conf": {
"isVpnBased":{
"accountType": "Primary"
}
}
}
]
}
}
}
]
}
/*
Expected result
output1 = [
{
"id": "dm11022",
"information":{
"description": "Customer",
"owner": {
"primary":{
"name": "James",
"phone": "NA"
},
"others": [
{
"$isMultiAccount": "./Yes"
}
]
}
}
},
{
"id": "dm12022",
"information":{
"description": "Customer",
"owner": {
"primary":{
"name": "James",
"phone": "NA"
},
"others": [
{
"$isMultiAccount": "./No"
}
]
}
}
}
]
// $isMultiAccount account do not exist in this object
output2 = [
{
"id": "dm12022",
"information":{
"description": "Customer",
"owner": {
"primary":{
"name": "James",
"phone": "NA"
},
"others": [
{
"conf": {
"isVpnBased":{
"accountType": "Primary"
}
}
}
]
}
}
}
]
*/
const item = {
"domains": [
{
"id": "dm11022",
"information":{
"description": "Customer",
"owner": {
"primary":{
"name": "James",
"phone": "NA"
},
"others": [
{
"$isMultiAccount": "./Yes"
}
]
}
}
},
{
"id": "dm12022",
"information":{
"description": "Customer",
"owner": {
"primary":{
"name": "James",
"phone": "NA"
},
"others": [
{
"$isMultiAccount": "./No"
}
]
}
}
},
{
"id": "dm12022",
"information":{
"description": "Customer",
"owner": {
"primary":{
"name": "James",
"phone": "NA"
},
"others": [
{
"conf": {
"isVpnBased":{
"accountType": "Primary"
}
}
}
]
}
}
}
]
}
const [areMulti, areNotMulti] = _.reduce(item.domains, (current, next) => {
return _.has(next, ‘information.owner.others.$isMultiAccount’)
? [current[0].concat(next), current[1]]
: [current[0], current[1].concat(next)];
}, [[], []]);
console.log(areMulti);
console.log(areNotMulti);
Since item.domains.information.owner.others is an array, you need to tackle it as follows:
let multi = [];
let notMulti = [];
_.each(item.domains, function (obj) {
if (obj.information.owner.others.length && _.has(obj.information.owner.others[0], '$isMultiAccount'))
multi.push(obj);
else
notMulti.push(obj);
});
console.log(multi);
console.log(notMulti);
Unfortunately, you have to iterate over the domains array as well ass on the owner.others array to determine if the object with specific key sits inside.
So the algorithm has O(n*m) complexity.
If you ask for a lodash function seems that the partition method is what you're looking for
As docs says:
Creates an array of elements split into two groups, the first of which contains elements predicate returns truthy for, the second of which contains elements predicate returns falsey for. The predicate is invoked with one argument: (value).
So it will be like:
_.partition(
item.domains,
e => _.some(
_.get(e, 'information.owner.others'),
el => _.has(el,"$isMultiAccount")
)
);
Watch out - some hack available!
However, if the you're 100% sure that the element you're looking for will be always at specific index (for example it is supposed to be always as first element - so index 0) you can limit the algorithm to have linear complexity O(n) as only the size of the domains array will matter in terms of performance.
The hackish solution assuming fixed array index=0:
_.partition(
item.domains,
e => _.has(e, 'information.owner.others.0.$isMultiAccount')
);
NOTE
Using lodash makes code a bit easier to read but of course it creates some performance overhead anyway.
This is a nested json file and I am trying to arrange it in a readable format to display in a table
I tried to manually put all the keys and values with in a for loop but there should be an elegant way to achieve this and hence I am reaching SO.
The actual JSON is quite a nested one and needed time to execute data with 500k rows
The result should be enhanced JSON with parent values appearing for child values as well
var property = {
"data": [{
"ID": "123456",
"name": "Coleridge st",
"criteria": [
{
"type": "type1",
"name": "name1",
"value": "7",
"properties": []
},
{
"type": "type2",
"name": "name2",
"value": "6",
"properties": [
{
"type": "MAX",
"name": "one",
"value": "100"
}, {
"type": "MIN",
"name": "five",
"value": "5"
}
]
},
{
"type": "type3",
"name": "name3",
"value": "5",
"properties": [{
"type": "MAX1",
"name": "one6",
"value": "1006"
}, {
"type": "MIN2",
"name": "five6",
"value": "56"
}]
}
]
},
{
"ID": "456789",
"name": "New Jersy",
"criteria": [
{
"type": "type4",
"name": "name4",
"value": "6",
"properties": [{
"type": "MAX12",
"name": "one12",
"value": "10012"
}, {
"type": "MIN23",
"name": "five12",
"value": "532"
}]
}
]
}]
};
var output = [];
property.data.forEach(function (users) {
var multirows = {
id: users.ID,
name: users.name,
};
for (var i = 0; i < users.criteria.length; i++) {
var criterias = {
type: users.criteria[i].type,
name: users.criteria[i].name,
value: users.criteria[i].value,
}
var mat_contacts_rows;
if (!isEmpty(users.criteria[i].properties)) {
for (var j = 0; j < users.criteria[i].properties.length; j++) {
var property = {
type: users.criteria[i].properties[j].type,
name: users.criteria[i].properties[j].name,
value: users.criteria[i].properties[j].value
};
mat_contacts_rows = { ...multirows, ...{ criteria: criterias }, ...{ properties: property } };
output.push(mat_contacts_rows);
}
} else {
var property = [];
mat_contacts_rows = { ...multirows, ...{ criteria: criterias }, ...{ properties: property } };
output.push(mat_contacts_rows);
}
}
});
console.log(JSON.stringify(output, undefined, 2))
function isEmpty(obj) {
for (var key in obj) {
if (obj.hasOwnProperty(key))
return false;
}
return true;
}
I think this could be a great exercise to you to don't answer your question but to give you some tips. You should first look at : Lodash wish has a bunch of usefull method to help you doing what you'r trying to do.
In a second time you should avoir using .forEach or for loops and try using Array.prototype.map or Array.prototype.reduce