Compare and reduce complex array of objects - javascript

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

Related

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

Remove duplicate elements of an array, in an object of arrays, dynamically

I have checked other solutions but none fit the criterion of my problem
This solution does not have the ability to dynamically check each node
Problem summarized
I wish to create an algorithm that is able to check an object that has nodes of different data types, for duplicated objects in nodes that are specifically of the datatype array.
I have the following dataset:
task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 1 }, { id: 2 }],
vendor: [{ id: 2 }, { id: 2 }, { id: 3 }],
};
I wish to be able to dynamically check which of the objects (or nodes? and the algo has to recognize that it is an array) has duplicates, and reduce them to be in this form:
task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 2 }],
vendor: [{ id: 2 }, { id: 3 }],
};
EDIT
The algorithm needs to be able to handle a dynamic number of nodes (example 1), however , the duplicates will only happen 1 level down (Thanks for pointing out).
example 1 (there is 1 less node here ) :
task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 2 }],
};
Here is my proposed solution to remove duplicate elements from any array in the task object:
const uniq = array => {
const map = {};
const result = [];
for (let i = 0; i < array.length; i++) {
// since elements can be objects, need to do a deep comparison.
const element = JSON.stringify(array[i]);
if (map[element] === undefined) {
map[element] = true;
result.push(array[i]);
}
}
return result;
}
const task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 1 }, { id: 2 }],
vendor: [{ id: 2 }, { id: 2 }, { id: 3 }],
};
for (const key in task) {
if (Array.isArray(task[key])) {
task[key] = uniq(task[key])
}
}
console.log('deduped:', task);

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

Sort JavaScript Array having the array of Object

Can you please suggest me the best way to sort the below array by the priority based on the name of the section. I am more worried on the time complexity as my array in real consist of 100 000 records.
I am okay also to change the array structure if there any better way to store
[{
id: 'field1',
sections: [{
name: 'Top_Section',
priority: 3
},
{
name: 'Bottom_Section',
priority: 3
}
]
},
{
id: 'field2',
sections: [{
name: 'Top_Section',
priority: 2
},
{
name: 'Bottom_Section',
priority: 4
}
]
},
{
id: 'field3',
sections: [{
name: 'Top_Section',
priority: 1
},
{
name: 'Bottom_Section',
priority: 1
}
]
},
{
id: 'field4',
sections: [{
name: 'Top_Section',
priority: 4
},
{
name: 'Bottom_Section',
priority: 2
}
]
}
];
Like I wanted to sort priority based on the Top_Section so my expected output should be as below
as the field3 is having priority 1 and field2 is having priority 2 etc.
[
{
id: 'field3',
sections: [
{ name: 'Top_Section', priority: 1 },
{ name: 'Bottom_Section', priority: 1 }
]
},
{
id: 'field2',
sections: [
{ name: 'Top_Section', priority: 2 },
{ name: 'Bottom_Section', priority: 4 }
]
},
{
id: 'field1',
sections: [
{ name: 'Top_Section', priority: 3 },
{ name: 'Bottom_Section', priority: 3 }
]
},
{
id: 'field4',
sections: [
{ name: 'Top_Section', priority: 4 },
{ name: 'Bottom_Section', priority: 2 }
]
}
];
I'm assuming here that 'Top_Section' is always on the first position in the sections array.
I'm also assuming that there will be only two types of priority types: 'Top_Section' and 'Bottom_Section'
let list = [{
id: 'field1',
sections: [{
name: 'Top_Section',
priority: 3
},
{
name: 'Bottom_Section',
priority: 3
}
]
},
{
id: 'field2',
sections: [{
name: 'Top_Section',
priority: 2
},
{
name: 'Bottom_Section',
priority: 4
}
]
},
{
id: 'field3',
sections: [{
name: 'Top_Section',
priority: 1
},
{
name: 'Bottom_Section',
priority: 1
}
]
},
{
id: 'field4',
sections: [{
name: 'Top_Section',
priority: 4
},
{
name: 'Bottom_Section',
priority: 2
}
]
}
];
function sortBy(priorityName) {
let priorityPosition = (priorityName == 'Top_Section') ? 0 : 1;
return (a, b) => {
return a['sections'][priorityPosition].priority - b['sections'][priorityPosition].priority;
}
}
console.log( list.sort(sortBy('Top_Section')) );
Let's create a comparator
function compare(a, b) {
var sumA = 0;
var sumB = 0;
for (var section of a.sections) sumA += section.priority;
for (var section of b.sections) sumB += seciton.priority;
return sumB - sumA;
}
arr.sort(compare);
The comparator returns positive if the first parameter is greater, negative if the second parameter is greater and 0 if they are equal. I assumed that the lowest the numeric value of the sum of the priorities, the greater the item is.

Filter array inside array

I have the array as below
test_list = [
{
id: 1,
test_name: 'Test 1',
members: [
{
user_id: 3
},
{
user_id: 4
}
],
},
{
id: 2,
test_name: 'Test 2',
members: [
{
user_id: 4
},
{
user_id: 5
},
],
},
{
id: 3,
test_name: 'Test 2',
members: [
{
user_id: 8
},
{
user_id: 10
},
],
}
]
I want to filter the test for specific user_id, example if user_id = 4 I would like to have this result
{
id: 1,
...
},
{
id: 2,
...
},
I have tried with this but it only return the member
test_list.filter(function(item) {
item.members.filter(function(member) {
if(member.user_id === 4) {
return item;
}
});
})
Would anyone please help me in this case?
Check if .some of the objects in the members array have the user_id you're looking for:
test_list = [{
id: 1,
test_name: 'Test 1',
members: [{
user_id: 3
},
{
user_id: 4
}
],
},
{
id: 2,
test_name: 'Test 2',
members: [{
user_id: 4
},
{
user_id: 5
},
],
},
{
id: 3,
test_name: 'Test 2',
members: [{
user_id: 8
}]
}
];
const filtered = test_list.filter(
({ members }) => members.some(
({ user_id }) => user_id === 4
)
);
console.log(filtered);
You could use .reduce() and .filter() method of array to achieve required result.
Please check below working code snippet:
const arr = [{"id":1,"test_name":"Test 1","members":[{"user_id":3},{"user_id":4}]},{"id":2,"test_name":"Test 2","members":[{"user_id":4},{"user_id":5}]},{"id":3,"test_name":"Test 2","members":[{"user_id":8}]}];
const data = arr.reduce((r,{ members,...rest }) => {
let rec = members.filter(o => o.user_id === 4)
if(rec.length){
rest.members = rec;
r.push(rest);
}
return r;
},[]);
console.log(data);
Hope this works.
var members = item.members;
var filterById =members.filter((item1)=>{
return (item1.user_id===4)
});
return filterById.length > 0;
});
console.log(test_List_by_id)```

Categories

Resources