How can I get the result from arr1 and arr2, When the ID matches I need to copy the content from arr1 - javascript

How can I get the result from arr1 and arr2, When the ID matches I need to copy the content from arr1
const arr1 = [
{ id: 1, name: "omar" },
{ id: 2, name: "laith" },
{ id: 3, name: "aref" },
]
const arr2 = [
{ id: 1, rating: "good" },
{ id: 2, rating: "very good" },
{ id: 2, rating: "very good" },
{ id: 3, rating: "Excellence" },
{ id: 3, rating: "Excellence" },
]
//expected output
const result = [
{ id: 1, rating: "good", name: "omar" },
{ id: 1, rating: "good", name: "omar" },
{ id: 2, rating: "very good", name: "laith" },
{ id: 3, rating: "Excellence", name: "aref" },
{ id: 3, rating: "Excellence", name: "aref" },
]

use reduce with filter
const arr1 = [ { id: 1, name: "omar" }, { id: 2, name: "laith" }, { id: 3, name: "aref" }, ];
const arr2 = [ { id: 1, rating: "good" }, { id: 2, rating: "very good" }, { id: 2, rating: "very good" }, { id: 3, rating: "Excellence" }, { id: 3, rating: "Excellence" }, ];
const result = arr1.reduce((acc,item) => {
const list = arr2.filter(i => i.id === item.id)
return [...acc, ...list.map(i => ({id: i.id,rating:i.rating, name: item.name}))]
}, [])
console.log(result)

Basically with a loop. Actually 2. Using a temporary object (result) as dictionary (or map) we can make it efficient searching for a match to each id. This is of complexity O(n) basically.
const arr1 = [ { id: 1, name: "omar" }, { id: 2, name: "laith" }, { id: 3, name: "aref" }, ];
const arr2 = [ { id: 1, rating: "good" }, { id: 2, rating: "very good" }, { id: 2, rating: "very good" }, { id: 3, rating: "Excellence" }, { id: 3, rating: "Excellence" }, ];
var result = {}
arr1.forEach(function(item1) {
result[item1.id] = item1;
});
arr2.forEach(function(item2) {
result[item2.id] = (result[item2.id] || item2)
result[item2.id]['rating'] = item2.rating
})
result = Object.values(result)
console.log(result)

Related

How to reduce an array and add a count as a new field?

I have an array of objects, however i need the array to add a count onto each object, and also remove any duplicates. Is there a simple way to achieve this?
CURRENT
[
{ id: 2, name: 'Adventure' },
{ id: 6, name: 'Crime' },
{ id: 2, name: 'Adventure' },
{ id: 3, name: 'Beautiful' },
{ id: 7, name: 'Drama' },
{ id: 2, name: 'Adventure' }
]
EXPECTED
[
{ id: 2, name: 'Adventure', count: 3 },
{ id: 6, name: 'Crime', count: 1 },
{ id: 3, name: 'Beautiful', count: 1 },
{ id: 7, name: 'Drama', count: 1 }
]
let current = [
{ id: 2, name: 'Adventure' },
{ id: 6, name: 'Crime' },
{ id: 2, name: 'Adventure' },
{ id: 3, name: 'Beautiful' },
{ id: 7, name: 'Drama' },
{ id: 2, name: 'Adventure' }
]
let expected = current.reduce((acc, cur) => {
let curFind = acc.find(item => item.id === cur.id)
if (curFind) {
curFind.count++
return acc
} else {
return [...acc, {
...cur,
count: 1
}]
}
}, [])
console.log('expected:', expected)

Javascript - Group by data from object arrays

I have the object arrays like below:
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 }
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 }
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 }
]
};
And what I want is to group by id, name and list out rating belonging its like below
const users = [
{
id: 1,
name: "Spider-man",
rating: {top: 1, middle: 4.5, bottom: 5}
},
{
id: 2,
name: "Iron man",
rating: {top: 3, middle: 3.5, bottom: 2}
},
{
id: 3,
name: "Hulk",
rating: {top: 5, middle: 1.5, bottom: 4}
}
];
I've tried this approach but seems it can achieve in more ways such as .reduce, for...of with more elegant, right?
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 }
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 }
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 }
]
};
var result = obj.top.map(x => ({
id: x.id,
name: x.name,
rating: {
top: obj.top.find(t => t.id === x.id).rating,
middle: obj.middle.find(t => t.id === x.id).rating,
bottom: obj.bottom.find(t => t.id === x.id).rating,
}
}));
console.log(result);
Any other ways to achieve it? Thanks in advance.
You need to map one of the subarrays to find each character's rating, so I think your current approach is pretty reasonable. You can make it a bit less repetitive by making an array of the properties (top, middle, bot) beforehand, then iterating over them instead of listing each different one:
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 }
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 }
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 }
]
};
const props = ['top', 'middle', 'bottom'];
var result = obj.top.map(x => ({
id: x.id,
name: x.name,
rating: Object.fromEntries(
props.map(prop =>
[prop, obj[prop].find(t => t.id === x.id).rating]
)
)
}));
console.log(result);
Another approach that's less computationally complex:
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 }
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 }
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 }
]
};
const byName = {};
for (const [prop, arr] of Object.entries(obj)) {
for (const item of arr) {
byName[item.name] ??= { ...item, rating: {} };
byName[item.name].rating[prop] = item.rating;
}
}
console.log(Object.values(byName));
You could do it in a one-liner way
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 },
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 },
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 },
],
};
const res = Array.from(
Object.entries(obj)
.flatMap(([rater, ratee]) =>
ratee.map(({ id, name, rating }) => ({
id,
name,
[rater]: rating,
}))
)
.reduce(
(acc, { id, ...restInfo }) =>
acc.set(id, { ...(acc.get(id) || {}), ...restInfo }),
new Map()
)
).map(([id, { name, ...rating }]) => ({ id, name, rating }));
console.log(res);
Using Dictionary along with Logical nullish assignment (??=)
The main idea includes 2 steps:
Loop all [key, values] of the object.
Inner each the values of the object, we loop to determine which the user's rating along with key belongs by user.id.
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 }
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 }
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 }
]
};
// Refactor code: using Dictionary along with `Logical nullish assignment (??=)` .
var result = Object.entries(obj).reduce((acc, [key, values]) => {
values.forEach(v => {
acc[v.id] ??= {...v, rating: {}};
acc[v.id].rating[key] = v.rating;
});
return acc;
}, {});
console.log(Object.values(result));
/* Old versions: using Array approach
var result = Object.entries(obj).reduce((acc, [key, values]) => {
values.forEach(v => {
var x = acc.find(r => r.id === v.id);
if(x !== undefined){
x.rating[key] = v.rating;
}else{
x = { id: v.id, name: v.name, rating: {[key]: v.rating} };
acc.push(x);
}
});
return acc;
}, []);
*/
More detailed explanation:
With the dictionary approach instead of array, you can achieve it with the highest performance both time and space complexity (as #CertainPerformance's comment).
From MDN Web docs said that:
The logical nullish assignment (x ??= y) operator only assigns if x is nullish (null or undefined).
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 }
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 }
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 }
]
};
const tempArr1 = Object.keys(obj).reduce((arr, key) => {
obj[key].forEach((item) => {
arr = [...arr, { ...item, rating: { [key]: item.rating } }];
});
return arr;
}, []);
const result = tempArr1.reduce((arr, el) => {
let tempObj = { ...el };
const index = arr.findIndex((tempItem) => tempItem.id === tempObj.id);
if (~index) {
arr[index] = {
...tempObj,
rating: {
...arr[index].rating,
...tempObj.rating
}
};
} else {
arr = [...arr, tempObj];
}
return arr;
}, []);
console.log(result);
const obj = {
top: [
{ id: 1, name: "Spider-man", rating: 1 },
{ id: 2, name: "Iron man", rating: 3 },
{ id: 3, name: "Hulk", rating: 5 }
],
middle: [
{ id: 1, name: "Spider-man", rating: 4.5 },
{ id: 2, name: "Iron man", rating: 3.5 },
{ id: 3, name: "Hulk", rating: 1.5 }
],
bottom: [
{ id: 1, name: "Spider-man", rating: 5 },
{ id: 2, name: "Iron man", rating: 2 },
{ id: 3, name: "Hulk", rating: 4 }
]
};
var result = [];
for(let [key, values] of Object.entries(obj))
for(let item of values){
let x = result.find(r => r.id === item.id);
if(x !== undefined){
x.rating[key] = item.rating;
}else{
x = { id: item.id, name: item.name, rating: {[key]: item.rating} };
result.push(x);
}
}
console.log(result);

How to flatten the nested Array?

How do I flatten the nested Array in the Array?
Here is the example input Array,
const input = [
{
id: 1,
name: 'Charles',
otherFields: [{
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}]
}, {
id: 4,
name: 'Charles',
otherFields: [{
id: 5,
name: 'Pung',
}, {
id: 6,
name: 'James',
}]
}
]
Output Array I want to get.
[{
id: 1,
name: 'Charles'
}, {
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}, {
id: 4,
name: 'Charles'
}, {
id: 5,
name: 'Pung',
}, {
id: 6,
name: 'James',
}]
I want to somehow get the output in one statement like
input.map((sth) => ({...sth??, sth.field...})); // I'm not sure :(
With flatMap you can take out the otherFields property, and returning an array containing the parent item and the other array:
const input = [{
id: 1,
name: 'Charles',
otherFields: [{
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}]
}];
console.log(
input.flatMap(({ otherFields, ...item }) => [item, ...otherFields])
);
For more than one level, you could take a recursive approach of flattening.
const
flat = ({ otherFields = [], ...o }) => [o, ...otherFields.flatMap(flat)],
input = [{ id: 1, name: 'Charles', otherFields: [{ id: 2, name: 'Pung' }, { id: 3, name: 'James', otherFields: [{ id: 4, name: 'Jane' }] }] }],
result = input.flatMap(flat);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

filter array of object from another array with multiple elements in javascript

I have object and an array:
const response = [
{ id: 1, product: 'EL' },
{ id: 2, product: 'AC' },
{ id: 3, product: 'AC' },
{ id: 4, product: 'AD' },
{ id: 5, product: 'DE' },
];
const elProd = [
"EL"
"DE"
];
i want to filter out the product which has product code in elProd array.
my expectation is below:
const response = [
{ id: 2, product: 'AC' },
{ id: 3, product: 'AC' },
{ id: 4, product: 'AD' },
];
what I tried :
response.filter(obj => {return obj.product == elProd .includes(obj.product)})
const response = [{
id: 1,
product: 'EL'
},
{
id: 2,
product: 'AC'
},
{
id: 3,
product: 'AC'
},
{
id: 4,
product: 'AD'
},
{
id: 5,
product: 'DE'
},
];
const elProd = [
"EL",
"DE"
];
const filteredresp = response.filter((resp) => elProd.indexOf(resp.product) !== -1);
console.log(filteredresp);
response.filter(obj => {return !elProd.includes(obj.product)});
You almost got it, but you have a typo. You need a comma in the elProd array. Here's the code:
const response = [
{ id: 1, product: "EL" },
{ id: 2, product: "AC" },
{ id: 3, product: "AC" },
{ id: 4, product: "AD" },
{ id: 5, product: "DE" },
];
const elProd = [
"EL", // <-- Add the comma.
"DE",
];
// Don't forget to negate the includes here to exclude those you don't want.
const filtered = response.filter((obj) => !elProd.includes(obj.product));
// Result.
console.log(filtered);
You need only the check with includes.
const
response = [{ id: 1, product: 'EL' }, { id: 2, product: 'AC' }, { id: 3, product: 'AC' }, { id: 4, product: 'AD' }, { id: 5, product: 'DE' }],
elProd = ["EL", "DE"],
result = response.filter(obj => !elProd.includes(obj.product));
console.log(result);
You could use filter and some
const response = [
{ id: 1, product: 'EL' },
{ id: 2, product: 'AC' },
{ id: 3, product: 'AC' },
{ id: 4, product: 'AD' },
{ id: 5, product: 'DE' },
];
const elProd = [
"EL",
"DE"
]
res=response.filter(o=>!elProd.some(p=>o.product==p))
console.log(res)

Merge Duplicate object in array

I have an array I need to merge duplicate values with the sum of amount.
What would be an efficient algorithm
var arr = [{
item: {
id: 1,
name: "Abc"
},
amount: 1
}, {
item: {
id: 1,
name: "Abc"
},
amount: 2
}, {
item: {
id: 2,
name: "Abc"
},
amount: 2
},{
item: {
id: 1,
name: "Abc"
},
amount: 2
}]
I need solution as
[{
item: {
id: 1,
name: "Abc"
},
amount: 5
}, {
item: {
id: 2,
name: "Abc"
},
] amount: 2
}]
simply use Object.values() with Array.reudce() to merge objects and then get the values:
var arr = [{ item: { id: 1, name: "Abc" }, amount: 1 }, { item: { id: 1, name: "Abc" }, amount: 2 }, { item: { id: 2, name: "Abc" }, amount: 2 },{ item: { id: 1, name: "Abc" }, amount: 2 }];
var result = Object.values(arr.reduce((a,curr)=>{
if(!a[curr.item.id])
a[curr.item.id] = Object.assign({},curr); // Object.assign() is used so that the original element(object) is not mutated.
else
a[curr.item.id].amount += curr.amount;
return a;
},{}));
console.log(result);
used map to catch em all :D
var arr = [{ item: { id: 1, name: "Abc" }, amount: 1 }, { item: { id: 1, name: "Abc" }, amount: 2 }, { item: { id: 2, name: "Abc" }, amount: 2 },{ item: { id: 1, name: "Abc" }, amount: 2 }];
var res = {};
arr.map((e) => {
if(!res[e.item.id]) res[e.item.id] = Object.assign({},e); // clone, credits to: #amrender singh
else res[e.item.id].amount += e.amount;
});
console.log(Object.values(res));

Categories

Resources