How to delete and add item in nested array object - javascript

I have nested array objects which have items in it. I want to remove item from id:4 except first item and add it id:5 object.
const data = [
{
id: 1,
items: [ { id:11 }, {id:12 } ],
},
{
id: 2,
items: [ { id:21 } ],
},
{
id: 3,
items: [ { id:31 } ],
},
{
id: 4,
items: [ { id:41 }, {id:42 } ],
},
{
id: 5,
items: [ { id:51 } ],
},
]
so my resultant array should be like this
const data = [
{
id: 1,
items: [ { id:11 }, {id:12 } ],
},
{
id: 2,
items: [ { id:21 } ],
},
{
id: 3,
items: [ { id:31 } ],
},
{
id: 4,
items: [ { id:41 } ],
},
{
id: 5,
items: [ {id:42 }, { id:51 } ],
},
]

I'll do it in two steps, first to get all of the items in the item with id 4 except the first one:
let moreItems = [];
data.forEach((item) => {
if (item.id === 4) {
while(item.items.length > 1) {
moreItems.push(item.items[item.items.length-1]);
item.items.pop();
}
}
});
moreItems will be the array to add to the items in the item with id 5.
data.forEach((item) => {
if (item.id === 5) {
if (moreItems.length > 0) {
item.items = item.items.concat(moreItems);
}
}
});

Maybe something like this?
let v = data[3].items.pop()
data[4].items.push(v)
The question was not the most clear. If you need to do this based on some condition or logic you will have to do that yourself.

if you need to copy all items from id=4, use this code:
data[4].items.push(data[3].items.splice(1,data[3].items.length));

Related

Being able to remove duplicate keys from an array of objects

I have a question about how I can delete the existing elements, for example, in my case "Tallas" is repeated, could you please help me? Thank you very much to those who are willing to help me to solve this problem
const data =
[ { atributos: { Tallas: [{ id: 0, name: 'XS' }, { id: 1, name: 'S' }] }}
, { atributos: { Calzado: [{ id: 0, name: '10' }, { id: 1, name: '9.5' }] }}
, { atributos: { Tallas: [{ id: 0, name: 'XS' }] }}
]
The idea is to have this json format with the last "Tallas" since it is the last one that I added through my dynamic form.
const expected =
[{ atributos: { Calzado: [{ id: 0, name: '10' }, { id: 1, name: '9.5' }] }}
, { atributos: { Tallas: [{ id: 0, name: 'XS' }] }}
]
How do I do this is there a way to do it, I've tried with filter plus the findindex but I can't get to eliminate the repetition of the json res= new.filter((arr, index, self) => index === self.findIndex( (t) => (t.attributes === arr.attributes )))
To unique the array of objects, we can use the Javascript Set module, if the array has complex nested objects, we can stringify each object before creating new Set data. this below function will unique the array of complex objects.
function unique_array(array = []) {
const newSetData = new Set(array.map((e) => JSON.stringify(e)));
return Array.from(newSetData).map((e) => JSON.parse(e));
}
this is a function that takes an array and return the same array but delete every duplicated item
function removeDuplicates(arr) {
return arr.filter((item,
index) => arr.indexOf(item) === index);
}
I didn't understant the part written in spanish so I hope this is what you are looking for
This is a solution specific to your question. this is not a generic solution.
const data = [
{
atributos: {
Tallas: [
{ id: 0, name: "XS" },
{ id: 1, name: "S" },
],
},
},
{
atributos: {
Calzado: [
{ id: 0, name: "10" },
{ id: 1, name: "9.5" },
],
},
},
{
atributos: {
Tallas: [
{ id: 0, name: "XS" },
{ id: 1, name: "S" },
],
},
},
];
function uniqueArray(array) {
const resultObject = array.reduce((acc, eachValue) => {
let keys = Object.keys(eachValue.atributos);
keys.forEach((eachKey) => {
if (!acc[eachKey]) {
acc[eachKey] = [];
}
let list = eachValue["atributos"][eachKey].map(
(each) => each.id + "-" + each.name
);
acc[eachKey].push(...list);
});
return acc;
}, {});
const resultArray = Object.keys(resultObject).reduce((acc, each) => {
let setData = Array.from(new Set(resultObject[each]));
acc.push({
atributos: {
[each]: setData.map((e) => {
return { id: e.split("-")[0], name: e.split("-")[1] };
}),
},
});
return acc;
}, []);
return resultArray;
}
const result = uniqueArray(data)
console.log("result ", JSON.stringify(result, null, 2));

Flattern object in nested array of arrays Javascript

I have an array of arrays, which contain objects, would like to get the value of a certain key and return it as a big array, have tried a nested map but it returns multiple array's rather than a single array.
const items = [
{
id: 1,
sub_items: [
{
id: 1
},
{
id: 2
},
{
id: 3
}
]
},
{
id: 2,
sub_items: [
{
id: 4
},
{
id: 5
},
{
id: 6
}
]
}
]
const subItemIDs = items.map( (item) =>
item.sub_items.map( (subItem) => subItem.id )
)
console.log(subItemIDs);
Expected output
[1, 2, 3, 4, 5, 6]
Actual output
[ [1,2,3], [4,5,6] ]
You can use arrays.flat(). I can provide more specific code once output is mentioned in the question
const arr1 = [0, 1, 2, [3, 4]];
console.log(arr1.flat());
// expected output: [0, 1, 2, 3, 4]
const arr2 = [0, 1, 2, [[[3, 4]]]];
console.log(arr2.flat(2));
// expected output: [0, 1, 2, [3, 4]]
You could take Array#flatMap to get a flat array from nested arrays.
const
items = [{ id: 1, sub_items: [{ id: 1 }, { id: 2 }, { id: 3 }] }, { id: 2, sub_items: [{ id: 4 }, { id: 5 }, { id: 6 }] }],
subItemIDs = items.flatMap(({ sub_items }) => sub_items.map(({ id }) => id));
console.log(subItemIDs);
Achieved this with:
const items = [
{
id: 1,
sub_items: [
{
id: 1
},
{
id: 2
},
{
id: 3
}
]
},
{
id: 2,
sub_items: [
{
id: 4
},
{
id: 5
},
{
id: 6
}
]
}
]
const subItemIDs = [].concat(...items.map( (item) =>
item.sub_items.map( (subItem) => subItem.id )
))
console.log(subItemIDs);
Sometimes, the obvious is the easiest:
Given a data structure that looks like this
const items = [
{ id: 1, sub_items: [ { id: 1 }, { id: 2 }, { id: 3 }, ] },
{ id: 2, sub_items: [ { id: 4 }, { id: 5 }, { id: 6 }, ] },
];
A trivial function like this
function extract_item_ids( items ) {
const ids = [];
for ( const item of items ) {
for ( const {id} of sub_items ) {
ids.push(id);
}
}
return ids;
}
should do the trick. If you want to collect the ids from a tree of any depth, it's just as easy:
function extract_item_ids( items ) {
const ids = [];
const pending = items;
while ( pending.length > 0 ) {
const item = pending.pop();
ids.push(item.id);
pending.push(...( item.sub_items || [] ) );
}
return ids;
}
And collecting the set of discrete item IDs is no more difficult:
If you want to collect the ids from a tree of any depth, it's just as easy:
function extract_item_ids( items ) {
const ids = new Set();
const pending = [...items];
while ( pending.length > 0 ) {
const item = pending.pop();
ids.add(item.id);
pending.push(...( item.sub_items || [] ) );
}
return Array.from(ids);
}
As is the case with most things JavaScript, you have several options. Some are more efficient than others, others have a certain stylistic purity, others might better speak to your fancy. Here are a few:
Array.flat
With array flat you can take your original code and have the JS Engine flatten the array down to a one-dimensional array. Simply append .flat() onto the end of your map.
const items = [
{ id: 1, sub_items: [ { id: 1 }, { id: 2 }, { id: 3 }, ] },
{ id: 2, sub_items: [ { id: 4 }, { id: 5 }, { id: 6 }, ] },
];
const subItemIds = items.map( (item) =>
item.sub_items.map( (subItem) => subItem.id )
).flat()
console.log(subItemIds);
Array.reduce
Another method is to use reduce to iterate over the object and build an accumulation array using Array.reduce. In the example below, when pushing onto the array, the spread operator (...) is used to break the array into elements.
const items = [
{ id: 1, sub_items: [ { id: 1 }, { id: 2 }, { id: 3 }, ] },
{ id: 2, sub_items: [ { id: 4 }, { id: 5 }, { id: 6 }, ] },
];
const subItemIds = items.reduce((arr,item) => (
arr.push(...item.sub_items.map((subItem) => subItem.id)), arr
),[])
console.log(subItemIds);
Other
Other answers here make use of custom functions or Array.flatMap, which should be explored as they could lead to more readable and efficient code, depending on the program's needs.

typescript/javascript remove object partial repetition in nested array of objects

I have nested array of objects that looks like this:
const nestedArray = [
[{ id: 1 }, { id: 2 }, { id: 3 }],
[{ id: 1 }, { id: 2 }],
[{ id: 4 }, { id: 5 }, { id: 6 }],
]
Since objects with id 1 and 2 are already together in nestedArray's first element I want to remove the second element and maintain other elements without petition as they are. The result should be like this:
const nestedArray = [
[{ id: 1 }, { id: 2 }, { id: 3 }],
[{ id: 4 }, { id: 5 }, { id: 6 }]
]
How do I write a filter function by id to get the expected result?
As I see in your example:
the id are unique in each subarray
duplicate sub-array elements only exist in the previous sub-array
if the first element of a sub-array exists in the previous sub-array then all the other elements must also be
const nestedArray =
[ [ { id: 1} , { id: 2} , { id: 3} ]
, [ { id: 1} , { id: 2} ]
, [ { id: 4} , { id: 5} , { id: 6} ]
]
function arrCleaning(arr)
{
for (let i=arr.length;i--;)
{
if (i>0 && arr[i-1].some(x=>x.id===arr[i][0].id) )
arr.splice(i,1)
}
}
arrCleaning( nestedArray )
// result
console.log( 'nestedArray = [' )
nestedArray.forEach(e=>console.log(' ',JSON.stringify(e).replaceAll('"',''),','))
console.log(' ]')
.as-console-wrapper { max-height: 100% !important; top: 0; }
.as-console-row::after { display:none !important; }
Try this:
const nestedArray = [
[{ id: 1 }, { id: 2 }, { id: 3 }],
[{ id: 1 }, { id: 2 }]
]
var newArr = nestedArray.flat(2).filter((x, index, self) => index === self.findIndex((t) => (t.id === x.id)));
console.log(newArr);

how can i build this function that takes an array of tree object and concatenates them into one tree object?

I'm trying to write a function called buildTree() that takes the following datastructure as an input, loops on every element to output a tree of a specific format:
this is an example of my datastructure:
let array = [
{
levelOne: [
{
id: 'a',
rowData: {}
}
]
},
{
levelOne: [
{
id: 'b',
children: {
levelTwo: [
{
id: 'c',
rowData: {}
}
]
}
}
]
},
{
levelOne: [
{
id: 'b',
children: {
levelTwo: [
{
id: 'd',
rowData: {}
}
]
}
}
]
}
]
if we pass the array to buildTree()
let result = this.buildTree(array);
the result should hold the following tree:
{
levelOne: [
{
id: 'a',
rowData: {}
},
{
id: 'b',
children: {
levelTwo: [
{
id: 'c',
rowData: {}
},
{
id: 'd',
rowData: {}
}
//two elements in this array since they share the id
]
}
}
]
}
another example would be:
let array2 = [
{
levelOne: [
{
id: 'a',
rowData: {}
}
]
},
{
levelOne: [
{
id: 'a',
children: {
levelTwo: [
{
id: 'b',
rowData: {}
}
]
}
}
]
},
{
levelOne: [
{
id: 'a',
children: {
levelTwo: [
{
id: 'b',
children: {
levelThree: [
{
id: 'c',
rowData: {}
}
]
}
}
]
}
}
]
},
{
levelOne: [
{
id: 'a',
children: {
levelTwo: [
{
id: 'b',
children: {
levelThree: [
{
id: 'd',
rowData: {}
}
]
}
}
]
}
}
]
}
];
let result2 = this.buildTree(array2)
result2 should hold :
{
levelOne: [
{
id: 'a',
rowData: {},
children: {
levelTwo: [
{
id: 'b',
rowData: {},
children: {
levelThree: [
{
id: 'c',
rowData: {}
},
{
id: 'd',
rowData: {}
}
]
}
}
]
}
}
]
}
keeping in mind that if two elements in array had the same id , then they should fall under the same children of their key in the result like shown in the example.
i wrote a helper function to get me the element on a specific level called getElementByLevel():
getElementByLevel(tree: any, level: number , count = 0){
// debugger;
if(tree){
let key = Object.keys(tree)[0]
let element = tree[key][0];
if(count<level){
count=count+1
return this.getElementByLevel(element.children,level , count)
}
else {
return element;
}
}
else {
return null;
}
}
and this is my unworking incomplete buildTree() function:
buildTree(mainArray: any[]){
let myTree = {};
mainArray.forEach((item , index) => {
if(index == 0){
myTree = {...item};
console.log(myTree);
}
else
{
debugger;
let myElement = this.getElementByLevel(myTree, 0);
let elementToAdd = this.getElementByLevel(mainArray[1],0 )
myElement = {...myElement, ...elementToAdd}
console.log(myElement);
myTree = myElement;
}
})
}
more info about the input datastructure:
-rowData is always on the final level of the tree.
-arrays of 'levelOne','levelTwo','levelThree' etc.. are singletons holding one object (only in the input)
-the keys ('levelOne','levelTwo','levelThree' etc..) are dynamic keys and need to remain in the datastructure as shown in the examples.
more info about the output tree:
-the elements with the same id and the same parent key(eg. levelOne) must have their children as siblings. an example of that is -array[1].levelOne[0]- and -array[2].levelOne[0]- resulting in sibling children in -result-
any ideas on how to build the buildTree() function would be appreciated
You will have to use recursion to first build a tree that has the id values as keys (for fast lookup in case of multiple occurrences of the same id). Then in a second phase you can then transform that structure so it has the "levelXXX" values as arrays -- which are not suitable for fast lookup by id:
function buildTree(array) {
function mergeByKeys(levelItem, result) {
for (let levelKey in levelItem) {
let idItems = result[levelKey] = result[levelKey] || {};
for (let {id, children, rowData} of levelItem[levelKey]) {
let item = idItems[id] = idItems[id] || {id};
if (children) item.children = mergeByKeys(children, item.children || {});
if (rowData) item.rowData = rowData;
}
}
return result;
}
function levelsToArrays(levelItem) {
for (let levelKey in levelItem) {
for (let { children } of (levelItem[levelKey] = Object.values(levelItem[levelKey]))) {
if (children) levelsToArrays(children);
}
}
}
let result = {};
for (let levelItem of array) mergeByKeys(levelItem, result);
levelsToArrays(result);
return result;
}
// Example 2:
let array2 = [{levelOne: [{id: 'a',rowData: {}}]},{levelOne: [{id: 'a',children: {levelTwo: [{id: 'b',rowData: {}}]}}]},{levelOne: [{id: 'a',children: {levelTwo: [{id: 'b',children: {levelThree: [{id: 'c',rowData: {}}]}}]}}]},{levelOne: [{id: 'a',children: {levelTwo: [{id: 'b',children: {levelThree: [{id: 'd',rowData: {}}]}}]}}]}];
let result2 = buildTree(array2)
console.log(result2);
Is this the correct structure you're searching for?
Input:
let structure = [
{
one: {
id: 'ISBWIS',
rowData: 346234,
children: [
{
two: {
id: 'UUEJSW',
rowData: 958793
}
}
]
}
},
{
one: {
id: 'KSDIWG',
rowData: 857262,
children: [
{
two: {
id: 'XJSHWQ',
rowData: 855582
}
}
]
}
},
{
one: {
id: 'ISBWIS',
children: [
{
two: {
id: 'KNWEJD',
rowData: 181132
}
}
]
}
},
{
one: {
id: 'ISBWIS',
children: [
{
two: {
id: 'KNWEJD',
children: [
{
three: {
id: 'JEISYS',
rowData: 454933
}
}
]
}
}
]
}
}
];
Output:
{
"one": [
{
"id": "ISBWIS",
"rowData": 346234,
"children": {
"two": [
{
"id": "UUEJSW",
"rowData": 958793
},
{
"id": "KNWEJD",
"rowData": 181132,
"children": {
"three": [
{
"id": "JEISYS",
"rowData": 454933
}
]
}
}
]
}
},
{
"id": "KSDIWG",
"rowData": 857262,
"children": {
"two": [
{
"id": "XJSHWQ",
"rowData": 855582
}
]
}
}
]
}

Combine arrays from two objects into a single object inline

I have two objects and some of their properties are identical and I need to combine these properties into a single array for another operation. Here are the objects:
const grippers = [
{
relevantRegisters: {
R: [
{ ID: 1 },
{ ID: 2 },
{ ID: 3 },
],
},
},
]
const pallets = [
{
relevantRegisters: {
R: [
{ ID: 1 },
{ ID: 2 },
{ ID: 3 },
],
},
},
]
Note that pallets and grippers are arrays, there can be more than one, so I cant just do pallets[0].relevantRegisters.R and take it from there. So it could be like this:
const grippers = [
{
relevantRegisters: {
R: [
{ ID: 1 },
{ ID: 2 },
{ ID: 3 },
],
},
},
{
relevantRegisters: {
R: [
{ ID: 1 },
{ ID: 2 },
{ ID: 3 },
],
},
},
{
relevantRegisters: {
R: [
{ ID: 1 },
{ ID: 2 },
{ ID: 3 },
],
},
},
]
I want to have a final array with the combined objects from the R: arrays, like this (not the values of the ID's, but the objects that contain the ID!):
[{ID: 1}, {ID: 2}, {ID: 3}, {ID: 1}, {ID: 2}, {ID: 3}]
Here is what I have tried:
const extractedR = [
...pallets
.map((pallet) => {
return pallet.relevantRegisters.R;
}),
...grippers
.map((gripper) => {
return gripper.relevantRegisters.R;
}),
]
However the result from this is an array of an array each containing the IDs. [Array(3), Array(3)]
Note: I don't need just the ID's, I need the object that contains the ID's as there are other properties within it that I also need, so I need to end up with an Array of 6 objects. Instead I end up with a 2x3 Array.
If I separate the two maps into variables (discovered it while trying to debug it) and spread the variables into array then it works, and so I've tried "double spreading" inline (don't know if that even works) like [...[...pallets(..),], ...[...grippers(..)]] but it also didnt work. I need to be able to do this inline.
You can use flatMap
const grippers = [
{
relevantRegisters: {
R: [
{ ID: 1 },
{ ID: 2 },
{ ID: 3 },
],
},
},
]
const pallets = [
{
relevantRegisters: {
R: [
{ ID: 1 },
{ ID: 2 },
{ ID: 3 },
],
},
},
]
const extractedR = [
...pallets
.flatMap((pallet:any) => {
return pallet.relevantRegisters.R;
}),
...grippers
.flatMap((gripper:any) => {
return gripper.relevantRegisters.R;
}),
]
console.log(extractedR)
Is this what you want?
const grippers = [
{
relevantRegisters: {
R: [
{ ID: 1 },
{ ID: 2 },
{ ID: 3 },
],
},
},
]
const pallets = [
{
relevantRegisters: {
R: [
{ ID: 1 },
{ ID: 2 },
{ ID: 3 },
],
},
},
]
var arrayInline = [].concat(grippers[0].relevantRegisters.R).concat(pallets[0].relevantRegisters.R);
console.log(arrayInline);
You can use concat function for this.
const grippers = [
{
relevantRegisters: {
R: [
{ ID: 1 },
{ ID: 2 },
{ ID: 3 },
],
},
},
]
const pallets = [
{
relevantRegisters: {
R: [
{ ID: 1 },
{ ID: 2 },
{ ID: 3 },
],
},
},
]
let newArray = [];
grippers.filter(e => newArray = newArray.concat(e.relevantRegisters.R))
pallets.filter(e => newArray = newArray.concat(e.relevantRegisters.R))
console.log(newArray);
You can use array reduce to get your result.
Working Code
const grippers = [{
relevantRegisters: {
R: [{
ID: 1
},
{
ID: 2
},
{
ID: 3
},
],
},
}, ]
const pallets = [{
relevantRegisters: {
R: [{
ID: 1
},
{
ID: 2
},
{
ID: 3
},
],
},
}, ]
console.log([...grippers.map(({
relevantRegisters: {
R
}
}) => R).reduce((arr, val) => [...arr, val]), ...pallets.map(({
relevantRegisters: {
R
}
}) => R).reduce((arr, val) => [...arr, val])])
const extracted = [...grippers[0].relevantRegisters.R, ...pallets[0].relevantRegisters.R]
with the new requirement you could do it like this
[].concat.apply([], [...grippers.map(x => x.relevantRegisters.R), ...pallets.map(x => x.relevantRegisters.R)]);

Categories

Resources