Join Array of Arrays on property - javascript

I have two objects as follows below. I would like to merge the contents of one of the array to the contents of the another array based on a property. I know that this is achievable by joining in database query but I was hoping to do the merge server side to better familiarize myself with javascript
const tasks = [
{
id: 1,
name: 'john'
items: [
{
name: 'dishes',
completed: false
}
]
},
{
id: 2,
name: 'jane'
items: [
{
name: 'sweep',
completed: true
},
{
name: 'vacuum',
completed: false
}
]
}
];
and
const progress = [
{
id: 1
items: [
{
name: 'dishes',
progression: 50
}
]
},
{
id: 2,
items: [
{
name: 'sweep',
progression: 100
},
{
name: 'vacuum',
progression: 10
}
]
}
]
How do I go about getting the object to look like below?
[
{
id: 1,
name: 'john'
items: [
{
name: 'dishes',
completed: false
progression: 50
}
]
},
{
id: 2,
name: 'jane'
items: [
{
name: 'sweep',
completed: true
progression: 100
},
{
name: 'vacuum',
completed: false
progression: 10
}
]
}
];
Cheers!

If you are sure that items will always have 1 item then below function should work for you
function merge(){
const merged = tasks.map(task=>{
let progres = progress.find(progres=>progres.id===task.id)
if(progres){
task.items = [{...task.items[0],...progres.items[0]}]
}
return task;
});
return merged;
}

Related

How to split recursive array into two categories based on specific field and also get the parent path?

I have confusion on recursive function to split recursive array into another recursive arrays. Let say I have an item and inside it there is packaged items (or children), and the children also have an item and children, there's no limitation about the recursion level.
The problem
I need to separate the paths of package item object that has isOptional true and paths of isOptional false. The function should return 2 categorized array and the value inside the array must be recursive just like the input structure. Please check the diagram below
Here's input example
const product = {
name: "Product 1",
packagedItems: [
{
id: 1,
isOptional: false,
item: {
name: "1#1",
packagedItems: [
{
id: 3,
isOptional: false,
item: {
name: "2#1",
packagedItems: [
{
id: 5,
isOptional: false,
item: {
name: "3#1",
packagedItems: []
}
},
{
id: 6,
isOptional: true,
item: {
name: "3#2",
packagedItems: []
}
}
]
}
}
]
}
},
{
id: 2,
isOptional: false,
item: {
name: "1#2",
packagedItems: [
{
id: 4,
isOptional: false,
item: {
name: "2#2",
packagedItems: [
{
id: 7,
isOptional: true,
item: {
name: "3#3",
packagedItems: []
}
},
{
id: 8,
isOptional: true,
item: {
name: "3#4",
packagedItems: []
}
}
]
}
}
]
}
}
]
};
Here's the diagram
enter image description here
What I've tried is only able to get parent's name but not building the same structure as the input
const getParents = (
packagedItems: PackagedItem[],
ancestors: (string | PackagedItem)[] = []
): any => {
for (let pack of packagedItems) {
if (pack.isOptional && !pack.item.packagedItems.length) {
return ancestors.concat(pack);
}
const found = getParents(
pack.item.packagedItems,
ancestors.concat(pack.item.name)
);
if (found) {
return found;
}
}
return undefined;
};
console.log(getParents(product.packagedItems));
only return
[
"1#1",
"2#1",
{
id: 6
isOptional: true
item: Object
}
]
Expected result would be two arrays like this.
const optionalTrue = [
{
id: 1,
isOptional: false,
item: {
name: "1#1",
packagedItems: [
{
id: 3,
isOptional: false,
item: {
name: "2#1",
packagedItems: [
{
id: 6,
isOptional: true,
item: {
name: "3#2",
packagedItems: []
}
}
]
}
}
]
}
},
{
id: 2,
isOptional: false,
item: {
name: "1#2",
packagedItems: [
{
id: 4,
isOptional: false,
item: {
name: "2#2",
packagedItems: [
{
id: 7,
isOptional: true,
item: {
name: "3#3",
packagedItems: []
}
},
{
id: 8,
isOptional: true,
item: {
name: "3#4",
packagedItems: []
}
}
]
}
}
]
}
}
];
const optionalFalse = [
{
id: 1,
isOptional: false,
item: {
name: "1#1",
packagedItems: [
{
id: 3,
isOptional: false,
item: {
name: "2#1",
packagedItems: [
{
id: 5,
isOptional: false,
item: {
name: "3#1",
packagedItems: []
}
}
]
}
}
]
}
}
];
Your function is going in the right direction, but the pack is a leaf, and matches the category, you should not continue with the recursive call. Also the collection into the ancestors array will not work well as you collect either pack or name in it.
Here is an implementation that gives the output you intended:
function filterOnLeaf(item, optional) {
return {
...item,
packagedItems: item.packagedItems.map(package => {
if (!package.item.packagedItems.length) { // Leaf
if (package.isOptional != optional) return null;
} else { // Internal
package = {
...package,
item: filterOnLeaf(package.item, optional)
};
if (!package.item.packagedItems.length) return null;
}
return package;
}).filter(Boolean)
};
}
const product = {name: "Product 1",packagedItems: [{id: 1,isOptional: false,item: {name: "1#1",packagedItems: [{id: 3,isOptional: false,item: {name: "2#1",packagedItems: [{id: 5,isOptional: false,item: {name: "3#1",packagedItems: []}},{id: 6,isOptional: true,item: {name: "3#2",packagedItems: []}}]}}]}},{id: 2,isOptional: false,item: {name: "1#2",packagedItems: [{id: 4,isOptional: false,item: {name: "2#2",packagedItems: [{id: 7,isOptional: true,item: {name: "3#3",packagedItems: []}},{id: 8,isOptional: true,item: {name: "3#4",packagedItems: []}}]}}]}}]};
const optionalTrue = filterOnLeaf(product, true);
const optionalFalse = filterOnLeaf(product, false);
console.log("optional is true:");
console.log(optionalTrue);
console.log("optional is false:");
console.log(optionalFalse);

How to filter array key by another array number key

I have 2 array, first array structure is:
items: [
{
name: "a",
items: [
{ name: "jack" },
{ name: "jose" },
]
},
{
name: "b",
items: [
{ name: "lara" },
{ name: "jo" },
]
},
{
name: "c",
items: [
{ name: "andy" },
{ name: "hary" },
]
}
]
and the second array:
number: [
0: [0, 1],
1: [1],
2: [0]
]
How to filter "items" by "number" and How can such an output be obtained? (the best solution)
{["jack", "jole"],["jo"],["andy"]}
A few maps would do it:
the output you wish is not valid JS so I made a nested array
const arr1 = [{ name: "a", items: [{ name: "jack" }, { name: "jose" }, ] }, { name: "b", items: [{ name: "lara" }, { name: "jo" }, ] }, { name: "c", items: [{ name: "andy" }, { name: "hary" }, ] } ], numbers = [ [0, 1], [1], [0] ];
const res = numbers
.map((arr, i) => arr
.map(key => arr1[i].items[key].name)
)
console.log(res)
If your number variable has to be an Object.
let items = [
{
name: "a",
items: [{ name: "jack" }, { name: "jose" }]
},
{
name: "b",
items: [{ name: "lara" }, { name: "jo" }]
},
{
name: "c",
items: [{ name: "andy" }, { name: "hary" }]
}
];
let number = {
0: [0, 1],
1: [1],
2: [0]
};
let result = []
for (const [key, value] of Object.entries(number)){
let names = []
value.forEach(value => {
names.push(items[key].items[value].name)
})
result.push(names)
}
console.log(result)

Compare two array of objects based on a properties value and return the matched

HI All I am having two array of object my aim is to compare them and filter out the matched result
my data looks like this
let data1 = [
{
name:'tom',
process:'flipkart',
master:'pharma',
profiles: [
{
level:'begginer',
language:'hindi',
role:['flp_admin','flp_teacher']
}
]
},
{
name:'jeo',
process:'amazon',
master:'science',
profiles: [
{
level:'begginer',
language:'english',
role:['amz_admin']
}
]
},
{
name:'jerry',
process:'email',
master:'it',
profiles: [
{
level:'begginer',
language:'urdu',
role:['eml_teacher']
}
]
}
]
let data2 = [
{
masterName:'Pharma',
businessProcess: [
{ label:'flipkart', value:'flipkart' },
{ label:'amazon', value:'amazon' }
]
},
{
masterName:'science',
businessProcess: [
{ label:'flipkart', value:'flipkart' },
{ label:'amazon', value:'amazon' }
]
},
{
masterName:'it',
businessProcess: [
{ label:'email', value:'email' },
{ label:'amazon', value:'amazon' }
]
}
I want to compare data1 with data2 and return the match from data2 if master of data1 matches with masterName of data2 and if business of data1 matches with businessProcess.label of data2.
Could anyone please tell me how can I do it?
You can use Array.filter and Array.find to loop over and find the matching items:
let data1 = [{
name: 'tom',
process: 'flipkart',
master: 'pharma',
profiles: [{
level: 'begginer',
language: 'hindi',
role: ['flp_admin', 'flp_teacher']
}]
},
{
name: 'jeo',
process: 'amazon',
master: 'science',
profiles: [{
level: 'begginer',
language: 'english',
role: ['amz_admin']
}]
},
{
name: 'jerry',
process: 'email',
master: 'it',
profiles: [{
level: 'begginer',
language: 'urdu',
role: ['eml_teacher']
}]
}
]
let data2 = [{
masterName: 'Pharma',
businessProcess: [{
label: 'flipkart',
value: 'flipkart'
},
{
label: 'amazon',
value: 'amazon'
}
]
},
{
masterName: 'science',
businessProcess: [{
label: 'flipkart',
value: 'flipkart'
},
{
label: 'amazon',
value: 'amazon'
}
]
},
{
masterName: 'it',
businessProcess: [{
label: 'email',
value: 'email'
},
{
label: 'amazon',
value: 'amazon'
}
]
}
];
console.log(data1.filter((d) => {
return data2.find((d2) => {
//check if data matername equals data1 master
// or if data1.process value exists in one of the item of businessProcess as value
return d2.masterName == d.master || d2.businessProcess.find(b => b.value === d.process);
});
}));

How would you change values/add to nested object data inside array of objects using Javascript?

const beers = [
{
id: '100',
name: 'stoneys'
},
{
id: '200',
name: 'budweiser'
},
{
id: '300',
name: 'miller'
},
{
id: '400',
name: 'corona'
}
];
const people = [
{
name: 'steve',
teams: [
{
name: 'pirates',
beers: ['100']
},
{
name: 'penguins',
beers: ['300']
}
]
},
{
name: 'jim',
teams: [
{
name: 'indians',
beers: ['200']
},
{
name: 'blue jackets',
beers: ['100', '400']
}
]
}
];
let newPeople = people.map(fan => {
fan.teams.map(team => {
team.beers.map(beer => beers.filter(brand => brand.id === beer)[0])
});
});
Above is a sample I put together to best demonstrate my question. I am having trouble understanding why nested mapping (.map()) of object arrays is not allowing me to alter the nested data. When I console log results, I am either getting an "[undefined, undefined]' or the unchanged "people" array.
I would like to return the same array as "people" except replace the nested "beers" array (people.teams.beers[]) with corresponding objects from the "beers" array. Example of a successful result below:
{
name: 'steve',
teams: [
{
name: 'pirates',
beers: [
{
id: '100',
name: 'stoneys'
}
]
},
{
name: 'penguins',
beers: [
{
id: '300',
name: 'miller'
}
]
}
]
}
Array.map expects a function which takes single array element as parameter and returns a mapped value. In your case you're not returning any value from mapping functions therefore you're getting undefined twice
const beers = [
{
id: '100',
name: 'stoneys'
},
{
id: '200',
name: 'budweiser'
},
{
id: '300',
name: 'miller'
},
{
id: '400',
name: 'corona'
}
];
const people = [
{
name: 'steve',
teams: [
{
name: 'pirates',
beers: ['100']
},
{
name: 'penguins',
beers: ['300']
}
]
},
{
name: 'jim',
teams: [
{
name: 'indians',
beers: ['200']
},
{
name: 'blue jackets',
beers: ['100', '400']
}
]
}
];
let newPeople = people.map(fan => {
let teams = fan.teams.map(team => {
let beer = team.beers.map(beer => beers.filter(brand => brand.id === beer)[0]);
return { name: team.name, beers: beer }
});
return { name: fan.name, teams: teams }
});
console.log(newPeople);

How to remove duplicated item in array of array

I have an array like that:
[{
id: 1,
name: 'Proposal'
},
{
id: 2,
name: 'Contract',
children: [
{
name: 'Approval',
component: '/approval'
},
{
name: 'Cancellation',
component: '/cancellation'
}
]
}]
and another like that:
[{
id: 1,
name: 'Proposal'
},
{
id: 2,
name: 'Contract',
children: [
{
name: 'Approval',
component: '/approval'
}
]
},
{
id: 3,
name: 'Example'
}]
My question is how is the best way to filter arrays, and remove one if have duplicated or more, even in array of children. Or the best, is like arrays merge!

Categories