Combine arrays from two objects into a single object inline - javascript

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)]);

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.

search and update within nested array with mongoose

simplified schema of a doc in my Model:
{
ar1: [
{
b: {
ar2: [{ _id: 1, value: 2 }],
},
},
{
b: {
ar2: [{ _id: 2, value: 2 }],
},
},
{
b: {
ar2: [{ _id: 1, value: 5 }],
},
},
];
}
now i want to update all elements of ar2 that have _id equal to 1 so I would obtain:
{
ar1: [
{
b: {
ar2: [{ _id: 1, value: 3 }],
},
},
{
b: {
ar2: [{ _id: 2, value: 2 }],
},
},
{
b: {
ar2: [{ _id: 1, value: 3 }],
},
},
];
}
The following does not work:
Model.updateMany({
'ar1.b.ar2._id' : 1
},{
'ar1.$[].b.ar2.$[].value' : 2
});
any suggestions ?
The idea is that i want to be able the elements in the nested array that obey the query and update them.
You can use $[] combine with $[<identifier>] to do that:
Model.update(
{},
{ $set: { "ar1.$[].b.ar2.$[el].value": 3 } },
{ arrayFilters: [ { "el._id": 1 } ] }
)

How to delete and add item in nested array object

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));

Compare and reduce complex array of objects

I have a ``dataset which is an array of objects for some items in a database that has the details of how long it will take in estimatedDays for a specific item to be shipped:
items : [
{
id: '1'
shippingMethods: [
{
id: 'STANDARD',
estimatedDays: 3,
},
{
id: 'TWODAY',
estimatedDays: 2,
},
{
id: 'NEXTDAY',
estimatedDays: 1,
},
]
},
{
id: '2'
// same shipping data as above but standard shipping will take 4 estimatedDays
},
{
id: '3'
// same shipping data as above but TWODAY shipping will take 3 estimatedDays
},
]
I am wondering if there is a reduce function that could compare each shippingMethod.id in each item and return a new array back only where shippingMethod.estimatedDays is greatest compared to all items.
So the end array would be an array of objects with (in this case) 3 shipping methods: STANDARD, TWODAY, and NEXTDAY.
Here you go with the reduce method,
reduce
var items = [
{
id: '1',
shippingMethods: [
{
id: 'STANDARD',
estimatedDays: 3
},
{
id: 'TWODAY',
estimatedDays: 2
},
{
id: 'NEXTDAY',
estimatedDays: 1
},
]
},
{
id: '2',
shippingMethods: [
{
id: 'STANDARD',
estimatedDays: 4
},
{
id: 'TWODAY',
estimatedDays: 2
},
{
id: 'NEXTDAY',
estimatedDays: 1
},
]
},
{
id: '3',
shippingMethods: [
{
id: 'STANDARD',
estimatedDays: 3
},
{
id: 'TWODAY',
estimatedDays: 3
},
{
id: 'NEXTDAY',
estimatedDays: 1
},
]
},
];
var outItems = items.reduce(function(accu, curr){
if(curr.shippingMethods) {
if(accu.length > 0) {
for(var i = 0; i < curr.shippingMethods.length; i++) {
var current = curr.shippingMethods[i];
if(accu[i].id === current.id && accu[i].estimatedDays < current.estimatedDays) {
accu[i] = current;
}
}
} else {
accu = curr.shippingMethods;
}
}
return accu;
}, []);
console.log(outItems);

Categories

Resources