Group array by nested object property and merge [closed] - javascript

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 13 days ago.
Improve this question
I have an array with following structure:
BasketDish
[
{
id: string;
quantity: number;
Dish: AsyncItem<Dish | undefined>;
basketID: string;
createdAt?: string | null;
updatedAt?: string | null;
basketDishDishId?: string | null;
}
]
Dish
[
{
id: string;
name: string;
price: number;
},
{
id: string;
name: string;
price: number;
}
]
I need to group the array by Dish.id and then create an array which accumulates the quantity and total price
From:
[
{
id: 1,
name: BBQ Burger,
price: 17
},
{
id: 2,
name: CheeseBurger,
price: 15
},
{
id: 2,
name: CheeseBurger,
price: 15
},
]
To expected result:
[
{
id: 1,
name: BBQ Burger,
price: 17,
total: 17,
quantity: 1
},
{
id: 2,
name: CheeseBurger,
price: 15,
total: 30,
quantity: 2
},
]
I tried a lot with groupBy and merge, but couldn't figure it out
UPDATE
Thanks #BioStunt
Just needed to update your solution instead of group by id i had to group by Dish.id
/**
* Merge Dishes with same id
*/
const groupedItems = chain(basketDishes)
/** group items by key "id" */
.groupBy(a => a.Dish?.id)
/** convert grouped items */
.map((items, id) => ({
id: id,
dishId: items[0]?.Dish?.id,
name: items[0].Dish?.name,
quantity: items.length,
total: items.reduce((acc, item) => acc + item.Dish?.price!, 0),
}))
/** get result of chain */
.value();

If I correctly understood your question, you should use chain + groupBy from lodash.
In your case you have base item array:
const basketDish = [
{ id: 1, name: 'BBQ Burger', price: 17 },
{ id: 2, name: 'CheeseBurger', price: 15 },
{ id: 2, name: 'CheeseBurger', price: 15 },
];
To merge this data use this:
const groupedItems = chain(basketDish)
/** group items by key "id" */
.groupBy('id')
/** convert grouped items */
.map((items, id) => ({
id: Number(id),
name: items[0].name,
quantity: items.length,
total: items.reduce((acc, item) => acc + item.price, 0)
}))
/** get result of chain */
.value();
Below is the console output:
groupedItems.forEach((item) =>
console.log(`${item.quantity} * ${item.name} | ${item.total}`)
);

Related

react js useState update the quantity

I am new to react. I have got an issue updating a quantity.
const[persons,setPersons] = useState(personLists)
if you console.log(persons) it will give output as below. Now I want to
update qty for particular misc index of particular person index .
I have two persons in below array and each person have further two misc array
[
{
id: 1,
name: "john",
gender: "m",
misc: [
{
id: 1,
name: "xxx",
qty: 1
},
{
id: 2,
name: "xxx1",
qty: 1
}
]
},
{
id: 2,
name: "mary",
gender: "f",
misc: [
{
id: 1,
name: "aaa",
qty: 1
},
{
id: 2,
name: "bbb",
qty: 1
}
]
},
]
Now i want to update qty under misc array for that particular person.I have a function that takes the index of person array and index of misc array as below.
const updatePersonMiscQty = (personIndex, miscIndex) => {
setPersons(persons =>
persons.map((person,key) => {
const found = person.misc.find(d => key === miscIndex);
if (found) {
found.qty += 1;
}
return person;
})
}
let say my personIndex is 0 and miscIndex= is 1
so when usse click the button It should look into first person array, go to second index of misc and update qty.
I am looking for a solutions
access the items by indexes and update
setPersons(persons => {
const miscItem = persons[personIndex]?.misc?.[miscIndex]
if (miscItem ) {
miscItem.qty += 1;
}
return [...persons];
}
})

Access the sum of multiple arrays in React

const App = () => {
const course = [{
id: 1,
name: 'Half Stack application development',
parts: [
{
name: 'Fundamentals of React',
exercises: 10,
id: 1
},
{
name: 'Using props to pass data',
exercises: 7,
id: 2
},
{
name: 'State of a component',
exercises: 14,
id: 3
}
]
},
{
name: 'Node.js',
id: 2,
parts: [
{
name: 'Routing',
exercises: 3,
id: 1
},
{
name: 'Middlewares',
exercises: 7,
id: 2
}
]
}
]
I am trying to calculate the sum of the exercises in each of the courses so I can get something at the end of each course which says Total exercises: 31 at the end of Half Stack Application Development and total exercises 10: at the end of Node.Js
I have tried
const totals = course.map(c => c.parts.map(c => c.exercises.map(c => c.reduce((a, b) => a + b, 0))))
but received c.exercises.map is not a function.
How could I calculate the sum of each of c.exercises?
exercises looks like this in the console:
(2) [Array(3), Array(2)]
0: (3) [10, 7, 14]
1: (2) [3, 7]
length: 2
This to calculate just the number of exercises per course
const calculateTotalExercises = course =>
course.map(c => c.parts.reduce((res, {
exercises
}) => res + exercises, 0))
const course = [{
id: 1,
name: 'Half Stack application development',
parts: [{
name: 'Fundamentals of React',
exercises: 10,
id: 1
},
{
name: 'Using props to pass data',
exercises: 7,
id: 2
},
{
name: 'State of a component',
exercises: 14,
id: 3
}
]
},
{
name: 'Node.js',
id: 2,
parts: [{
name: 'Routing',
exercises: 3,
id: 1
},
{
name: 'Middlewares',
exercises: 7,
id: 2
}
]
}
]
console.log(calculateTotalExercises(course))
Probably it will be more convenient to add the total of the exercise to the array like this
const calculateTotalExercises = course =>
course.map(c => ({...c, totalExercise : c.parts.reduce((res, p) => res + p.exercises, 0)}))
const course = [{
id: 1,
name: 'Half Stack application development',
parts: [{
name: 'Fundamentals of React',
exercises: 10,
id: 1
},
{
name: 'Using props to pass data',
exercises: 7,
id: 2
},
{
name: 'State of a component',
exercises: 14,
id: 3
}
]
},
{
name: 'Node.js',
id: 2,
parts: [{
name: 'Routing',
exercises: 3,
id: 1
},
{
name: 'Middlewares',
exercises: 7,
id: 2
}
]
}
]
console.log(calculateTotalExercises(course))
You could start by breaking the problem down. Here's how I solved this.
I created a function that finds the total number of exercises for one course
let totalExerciseForOneCourse = (parts) => {
return parts.reduce((prev, curr) => prev + curr.exercises, 0)
}
Then we use the map method to go through each course in the courses array returning a new array of objects with everything that was in the courses array and adding in a totalExercises object property
let newCourses = courses.map((course) => {
const total = totalExerciseForOneCourse(course.parts);
return Object.assign({}, course, {
totalExercises: total
})
})
Our totalExerciseForOneCourse function takes an array parameter and calculates the sum of all exercises for one course using the array.reduce method
newCourses contains our new array with all previous and new information
JSFiddle -
https://jsfiddle.net/swish933/9fwzysxa/
The sum of multiple arrays can be rendered in a single component looking like this
{c.parts.reduce((a, b) => a += b.exercises, 0)}
You can just do
let total = 0
courses.map(course => course.parts.map(part => total += part.exercises)
Edit:
Just in case you need to use reduce:
const total = courses.map(course => course.parts.reduce(e1,e2 => e1+e2 ))

How to get the aggregation of an array in javascript

I am trying to aggregate my list of orders im getting in my database into an array of orders with different prices.
Example of array from my db:
[{
id: 1,
price: 10,
item: 'apple'
}, {
id: 2,
price: 10,
item: 'apple',
}, {
id: 3,
price: 20,
item: 'apple'
}]
i want to aggregate the orders based on the price ... if the price is the same make them into one array
what i want to return:
[{
price: 10,
item: 'apple',
quantity: 2
}, {
price: 20,
item: apple,
quantity: 1
}]
so as seen above if the price is the same aggregate them to one object and increase the quantity and return that to my users.
const data = [{
id: 1,
price: 10,
item: 'apple'
}, {
id: 2,
price: 10,
item: 'apple',
}, {
id: 3,
price: 20,
item: 'apple'
}];
let x = data.reduce((items, item) => {
let found = false;
delete(item.id)
items.forEach(el => {
if (el.price == item.price && el.item == item.item) {
found = true;
el.quantity++;
}
})
if (!found) {
item.quantity = 1;
items.push(item)
}
return items
}, [])
console.log(x)

Add price of duplicate object to first unique object in array using JavaScript only [duplicate]

This question already has answers here:
Group array of object nesting some of the keys with specific names
(2 answers)
Closed 2 years ago.
Input array
[{ id: 1, title: 'shirt', price: 2000 },
{ id: 2, title: 'shirt', price: 4000},
{ id: 3, title: 'tshirt', price: 10000}]
Expected output
[{ id: 1, title: 'shirt', price: 6000 }, // 2000 + 4000
{ id: 3, title: 'tshirt', price: 10000}]
Have tried multiple ways to achieve but couldn't get a solution.
I'm able to get unique objects but need the addition of price as well
let result = products.filter((product, index, self) =>
index === self.findIndex((t) => (t.title === product.title))
)
console.log(result);
You could take an object as hash bale for same title and get the values from the object.
const
data = [{ id: 1, title: 'shirt', price: 2000 }, { id: 2, title: 'shirt', price: 4000}, { id: 3, title: 'tshirt', price: 10000}],
result = Object.values(data.reduce((r, o) => {
if (r[o.title]) r[o.title].price += o.price;
else r[o.title] = { ...o };
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Find index of object array

I'm stuck with the code. I actually want to find the index of elements in dataLayer using typescript/javascript.
track: { products },
dataLayers: { current: { cart: { items } } }
products?: IProduct[]
export interface IProduct {
id: string
quantity?: string
name?: string
}
items?: ICartItem[]
export interface ICartItem {
id: string
brand: string
name: string
quantity: number
}
track: { products }
products have {id,quantity}
dataLayers: { current: { cart: { items } } }
items have {id, brand, name, quantity }
Now I want to find the position/index of products, For Example:
Example: *
products:{
[{id: 'a123',quantity: '1'},{id:'a345', quantity:'2'}]
}
items:{
[{id: 'a123',brand:'pen',name: 'Reynolds', quantity: '1'}, {id: 'a143',brand:'pencil',name: 'Nataraj', quantity: '3'}, {id: 'a122',brand:'pen',name: 'Parker',quantity: '1'},{id:'a345',brand:'Eraser',name: 'Faber-Castell', quantity:'2'}]
}
position of {id: 'a123',quantity: '1'} should be 1 and position of {id:'a345', quantity:'2'} should be 4
My code looks like below:
I have used map to get id from products as shown
const id = products.map(product => { return product.id})
now I want to find index/position of those products in items.so I tried like below
let position = filter((item: ICartItem) => {
if(id.includes(item.id)){
return {id}
}
}).findindex(id)
i.e.,
const id = products.map(product => { return product.id})
let position = filter((item: ICartItem) => {
if(id.includes(item.id)){
return {id}
}
}).findindex(id)
but I getting error
Argument of type 'string[]' is not assignable to parameter of type '(value: ICartItem, index: number, obj: ICartItem[]) => unknown'.
Type 'string[]' provides no match for the signature '(value: ICartItem, index: number, obj: ICartItem[]): unknown'.ts(2345)
an Some help me in finding position/index of the filtered product?
After map you can chain .indexOf() to get the Index of the object and Index of a345 would be 3 not 4 because indexes are zero based in an array
let items = [{
id: 'a123',
brand: 'pen',
name: 'Reynolds',
quantity: '1'
}, {
id: 'a143',
brand: 'pencil',
name: 'Nataraj',
quantity: '3'
}, {
id: 'a122',
brand: 'pen',
name: 'Parker',
quantity: '1'
}, {
id: 'a345',
brand: 'Eraser',
name: 'Faber-Castell',
quantity: '2'
}]
let index= items.map(function(e) {
return e.id;
}).indexOf('a345')
console.log(`Index=${index}`)
console.log(`position= ${index+1}`)
You can chain map and indexOf to get result as an array with positions.
const products = [
{ id: 'a123', quantity: '1' },
{ id: 'a345', quantity: '2' },
];
const items = [
{ id: 'a123', brand: 'pen', name: 'Reynolds', quantity: '1' },
{ id: 'a143', brand: 'pencil', name: 'Nataraj', quantity: '3' },
{ id: 'a122', brand: 'pen', name: 'Parker', quantity: '1' },
{ id: 'a345', brand: 'Eraser', name: 'Faber-Castell', quantity: '2' },
];
const result = products.map(product => items.map(item => item.id).indexOf(product.id) + 1);
console.log(result)
If array with positions needs to return id as well then you can do:
const products = [
{ id: 'a123', quantity: '1' },
{ id: 'a345', quantity: '2' },
];
const items = [
{ id: 'a123', brand: 'pen', name: 'Reynolds', quantity: '1' },
{ id: 'a143', brand: 'pencil', name: 'Nataraj', quantity: '3' },
{ id: 'a122', brand: 'pen', name: 'Parker', quantity: '1' },
{ id: 'a345', brand: 'Eraser', name: 'Faber-Castell', quantity: '2' },
];
const result = products.map(product => {
const id = product.id;
return {
id,
position: items.map(item => item.id).indexOf(id) + 1
}
});
console.log(result)
You can try:
const ids = products.map( product => product.id);
const positions = items.map( ( item, i ) => {
if( ids.includes(item.id)){
return{
position: i + 1,
id: item.id
}
}
return null
}).filter(Boolean)
//[ { position: 1, id: 'a123' }, { position: 4, id: 'a345' } ]

Categories