I'm still pretty new to Typescript so I've been looking at all the provided solutions but I'm still stuck with a complex nested array. I have the following structure:
data = [{
"property1_1": "value1_1",
"property1_2": "value1_2",
"property1_3": [
[{
"subproperty1_1_1": "subvalue1_1_1",
"subproperty1_1_2": "subvalue1_1_2"
}],
[{
"subproperty1_2_1": "subvalue1_2_1",
"subproperty1_2_2": "subvalue1_2_2"
}]
]
},
{
"property2_1": "value2_1",
"property2_2": "value2_2",
"property2_3": [
[{
"subproperty2_2_1": "subvalue2_2_1",
"subproperty2_2_2": "subvalue2_2_2"
}],
[{
"subproperty2_2_1": "subvalue2_2_1",
"subproperty2_2_2": "subvalue2_2_2"
}]
]
}
]
and I would like to achieve a simple array with objects looking like:
data = [{
"property1_1": "value1_1",
"property1_2": "value1_2",
"subproperty1_1_1": "subvalue1_1_1",
"subproperty1_1_2": "subvalue1_1_2",
"subproperty1_2_1": "subvalue1_2_1",
"subproperty1_2_2": "subvalue1_2_2"
},
{
"property2_1": "value2_1",
"property2_2": "value2_2",
"subproperty2_1_1": "subvalue2_1_1",
"subproperty2_1_2": "subvalue2_1_2",
"subproperty2_2_1": "subvalue2_2_1",
"subproperty2_2_2": "subvalue2_2_2"
}
]
I've already achieved to collect the subproperties into one array like doing:
const allDataConv = [];
data.forEach(dateninput => {
dateninput.propertyname.forEach(item => {
item.forEach(lastitem => {
allDataConv.push({key: lastitem.description, title: lastitem.name});
});
});
});
return allDataConv;
But that's not what I want to achieve. I'm stuck with the question: How can I apply the double nested objects into the corresponding parent object?
You could iterate over your object keys and check if the value is an array. If it's an array use flat(1) to flatten it and then iterate over it's children. Use Object.assign to add the child object keys to your root object and delete the key which had the array as a value.
Array.flat is an ESNext feature, you may need a polyfill for it in older browsers or use another for-of loop.
const input = data = [
{
"property1_1": "value1_1",
"property1_2": "value1_2",
"property1_3": [
[
{
"subproperty1_1_1": "subvalue1_1_1",
"subproperty1_1_2": "subvalue1_1_2"
}
],
[
{
"subproperty1_2_1": "subvalue1_2_1",
"subproperty1_2_2": "subvalue1_2_2"
}
],
],
},
{
"property2_1": "value2_1",
"property2_2": "value2_2",
"property2_3": [
[
{
"subproperty2_1_1": "subvalue2_2_1",
"subproperty2_1_2": "subvalue2_2_2"
}
],
[
{
"subproperty2_2_1": "subvalue2_2_1",
"subproperty2_2_2": "subvalue2_2_2"
}
]
]
}
];
function transformData(input) {
return input.map(obj => {
for(const prop in obj) {
if(obj.hasOwnProperty(prop) && Array.isArray(obj[prop])) {
for(const subObj of obj[prop].flat(1)) {
Object.assign(obj, subObj);
delete obj[prop];
}
}
}
return obj;
})
}
console.log(transformData(input));
Related
I have an array of object as follows. Currently there is only one object but invocations has an array of objects.
Depending on how many array of objects we have for invocations, we want to update the main array of objects. For e.g. if there are 2 objects in invocations, i want to separate those 2 invocations and replicate their parent object for both invocations.
This is not a regular iteration of array of objects and thats why i am not able to get the desired result. Any help is appreciated
const input = [
{
"name": "Test Data",
"invocations": [
{ "invocationId": "123" },
{ "invocationId": "125" },
]
},
]
const output = [
{
"name": "Test Data",
"invocations": [
{ "invocationId": "123" },
]
},
{
"name": "Test Data",
"invocations": [
{ "invocationId": "125" },
]
}
]
Here is a working example non-one-liner though!
For each object inside your array, you loop through the invocations property array and push each object inside a temp array along with all the other properties.
Then this array is concatenated with the final array.
const input = [
{
"name": "Test Data",
"invocations": [
{ "invocationId": "123" },
{ "invocationId": "125" },
]
},
]
let finalArray = []
Object.values(input).forEach(obj => {
let arr = []
obj.invocations.forEach(invoc => arr.push({...obj, invocations: [ invoc ]}))
finalArray = finalArray.concat(arr)
});
console.log(finalArray)
This will do it:
const splitInvocations = array => {
return array.reduce((result, obj) => {
const parentAssignedObjects = obj.invocations.map(invocation => ({ ...obj, invocations: [invocation] }));
return [...result, ...parentAssignedObjects];
}, []);
};
First, we loop through the array with reduce. We then map each invocation and return the parent object with a replaced value for the property invocations. We concat the reduce accumulator with the output of map using spread syntax.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
I have a jSOn with two arrays. I would like to merge all items of both arrays into a single array. Is there a jSOn path syntax i could use to give the desired output?
I have this:
[
"SomeArray",
{
"Branch1": {
"Branch2": {
"Branch3": {
"Array1": [
"Item1InArray1",
"Item2InArray1"
],
"Array2": [
"Item1InArray2",
"Item2InArray2"
]
}
}
}
}
]
And want this output: Its essentially two paths: [1].Branch1.Branch2.Branch3.Array1 and [1].Branch1.Branch2.Branch3.Array2
[
"Item1InArray1",
"Item2InArray1",
"Item1InArray2",
"Item2InArray2"
]
This simple example shows how you can achieve this having a full string-based path.
const arr = [
{
"Branch1": {
"Branch2": {
"Branch3": {
"Array1": [
"Item1InArray1",
"Item2InArray1"
],
"Array2": [
"Item1InArray2",
"Item2InArray2"
]
}
}
}
}
];
const paths = ["0.Branch1.Branch2.Branch3.Array1", "0.Branch1.Branch2.Branch3.Array2"];
const result = paths.map(path => path.split(".").reduce((unique, value) => unique[value], arr)).flat()
console.log(result)
You could simply get all nested arrays.
const
flat = item => item && typeof item === 'object'
? Array.isArray(item)
? item
: Object.values(item).flatMap(flat)
: [],
data = ["SomeArray", { Branch1: { Branch2: { Branch3: { Array1: ["Item1InArray1", "Item2InArray1"], Array2: ["Item1InArray2", "Item2InArray2"] } } } }],
items = data.flatMap(flat);
console.log(items);
{
"Branch1": {
"Branch2": {
"Branch3": {
"Array1": [
"Item1InArray1",
"Item2InArray1"
],
"Array2": [
"Item1InArray2",
"Item2InArray2"
]
}
}
}
}
]
let newArray = array1.reduce((main, curr)=> main.concat(curr.Branch1.Branch2.Array1, curr.Branch1.Branch2.Array1),[])
This is an example dataset:
const largeObject = {
"4249":{
"2018-07-25":[
{
"start":"2016-07-25T14:09:20.453Z",
"end":"2016-07-25T14:17:52.147Z"
}
]
},
"9939":{
"2018-07-25":[
{
"start":"2016-07-25T00:50:08.768Z",
"end":"2016-07-25T00:53:16.514Z"
}
]
},
"2149":{
"2018-07-25":[
{
"start":"2016-07-25T00:42:02.569Z",
"end":"2016-07-25T00:43:07.689Z"
}
]
},
"6929":{
"2018-07-24":[
{
"start":"2016-07-24T00:44:30.479Z",
"end":"2016-07-24T00:46:41.315Z"
}
]
},
"7930":{
"2018-07-24":[
{
"start":"2016-07-24T00:39:44.152Z",
"end":"2016-07-24T00:44:05.420Z"
}
]
},
"4796":{
"2018-07-22":[
{
"start":"2016-07-22T12:48:56.169Z",
"end":"2016-07-22T13:38:28.136Z"
}
]
}
}
I am trying to find the most efficient way to get to something like this:
const filteredObject = {
"2018-07-25": [
{
"start":"2016-07-25T14:09:20.453Z",
"end":"2016-07-25T14:17:52.147Z"
}, {
"start":"2016-07-25T00:50:08.768Z",
"end":"2016-07-25T00:53:16.514Z"
},
{
"start":"2016-07-25T00:42:02.569Z",
"end":"2016-07-25T00:43:07.689Z"
}
],
"2018-07-24": [
{
"start":"2016-07-24T00:44:30.479Z",
"end":"2016-07-24T00:46:41.315Z"
},
{
"start":"2016-07-24T00:39:44.152Z",
"end":"2016-07-24T00:44:05.420Z"
}
],
"2018-07-22": [
{
"start":"2016-07-22T12:48:56.169Z",
"end":"2016-07-22T13:38:28.136Z"
}
]
};
So far, I have done:
const filteredObject = {}
const newArr = []
for(key in largeObject){
console.log(largeObject[key])
}
And that gets rid of the random string, but still gets me this:
{ '2018-07-24':
[ { start: '2016-07-24T00:44:30.479Z',
end: '2016-07-24T00:46:41.315Z' } ] }
{ '2018-07-25':
[ { start: '2016-07-25T00:50:08.768Z',
end: '2016-07-25T00:53:16.514Z' } ] }
{ '2018-07-25':
[ { start: '2016-07-25T14:09:20.453Z',
end: '2016-07-25T14:17:52.147Z' } ] }
{ '2018-07-24':
[ { start: '2016-07-24T00:39:44.152Z',
end: '2016-07-24T00:44:05.420Z' } ] }
{ '2018-07-22':
[ { start: '2016-07-22T12:48:56.169Z',
end: '2016-07-22T13:38:28.136Z' } ] }
{ '2018-07-25':
[ { start: '2016-07-25T00:42:02.569Z',
end: '2016-07-25T00:43:07.689Z' } ] }
This is far as I've gotten. I still need to find a way to merge all the arrays with the same key values. It seems like I would need to iterate over this object, keep the date as the key, and push all of the arrays associated with that date-key into one array.
What would be the best way to handle something like this? I also want to do this as efficient as possible without having to iterate over the entire large object each time I check for the date-key and/or push the start/end object into an array of it's own.
You can start with Object.values() of your original data. This will give you an array of the values without the first level keys over which you can reduce(). Then for each of those break it into a key and value. Add the key with an array value if it's not already there and merge in the data.
const largeObject = { "4249":{ "2018-07-25":[ { "start":"2016-07-25T14:09:20.453Z","end":"2016-07-25T14:17:52.147Z"}]},"9939":{ "2018-07-25":[ { "start":"2016-07-25T00:50:08.768Z","end":"2016-07-25T00:53:16.514Z"}]},"2149":{ "2018-07-25":[ { "start":"2016-07-25T00:42:02.569Z","end":"2016-07-25T00:43:07.689Z"}]},"6929":{ "2018-07-24":[ { "start":"2016-07-24T00:44:30.479Z","end":"2016-07-24T00:46:41.315Z"}]},"7930":{ "2018-07-24":[ { "start":"2016-07-24T00:39:44.152Z","end":"2016-07-24T00:44:05.420Z"}]},"4796":{ "2018-07-22":[ { "start":"2016-07-22T12:48:56.169Z","end":"2016-07-22T13:38:28.136Z"}]}}
let filtered = Object.values(largeObject).reduce((a, c) => {
Object.entries(c).forEach(([k, v]) => {
(a[k] || (a[k] = [])).push(...v)
})
return a
},{})
console.log(filtered)
this is the array variable
let packageitems=
[
{
"packageid":1,
"items":[
{
"itemid":"1",
"name":"abc"
},
{
"itemid":"2",
"name":"cdr"
}
]
},
{
"packageid":2,
"items":[
{
"itemid":"1",
"name":"abc"
},
{
"itemid":"2",
"name":"xyz"
}
]
}
]
in angular typescript i am having one function:
updatePackageitem(newitem){
let objIndex = this.packageitems.findIndex(obj => obj.packageid==newitem.packageid);
Object.assign(this.packageitems[objIndex] , newitem);
}
newitem json is similar just the items array is different
when i assign using Object.assign the newitem array elements get copies to all rest json of this.packageitems even after getting the objIndex right
newitem =
{
"packageid":2,
"items":[
{
"itemid":"1",
"name":"def"
},
{
"itemid":"2",
"name":"pqr"
}
]
}
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);