Merge Object preserving it's value using addition in javascript - javascript

I have the js object array structured as given below,
items= [
{
discount: 27.6,
name: 'Floy Vandervort',
price: 230,
quantity: 3,
taxable: 662.4
},
{
discount: 122.88,
name: 'Adriel Abshire II',
price: 256,
quantity: 6,
taxable: 1413.12
},
{
discount: 159.66,
name: 'Tabitha Stroman',
price: 887,
quantity: 2,
taxable: 1614.34
},
{
discount: 27.6,
name: 'Floy Vandervort',
price: 230,
quantity: 3,
taxable: 662.4
},
{
discount: 122.88,
name: 'Adriel Abshire II',
price: 256,
quantity: 6,
taxable: 1413.12
},
{
discount: 159.66,
name: 'Tabitha Stroman',
price: 887,
quantity: 2,
taxable: 1614.34
},
{
discount: 27.6,
name: 'Floy Vandervort',
price: 230,
quantity: 3,
taxable: 662.4
},
{
discount: 122.88,
name: 'Adriel Abshire II',
price: 256,
quantity: 6,
taxable: 1413.12
},
{
discount: 159.66,
name: 'Tabitha Stroman',
price: 887,
quantity: 2,
taxable: 1614.34
}
]
I want to avoid duplication of objects based on name property. So I decided to merge them by preserving its evaluation as illustrated below,
Use Case
consider property name, here in above array Floy Vandervort repeats 3 times. To convert it into a single object, merge them into a single object by preserving the value by addition. So, the properties discount, quantity and taxable should be merged by addition except for price property.
I'm looking for an optimal solution, I achieved using iterating over the original array and pushing merged object to another array. I want to eliminate the complexity, is it possible? if yes, how? Here is the function I'm using
function(items) {
let filtered = [];
items.forEach((item) => {
if (!isContains(filtered, item)) {
filtered.push(item);
} else {
index = filtered.findIndex((x) => x.name === item.name);
filtered[index].discount += item.discount;
filtered[index].quantity += item.quantity;
filtered[index].taxable += item.taxable;
}
});
return filtered;
}
function isContains(items, ob) {
items.forEach((item) => {
if (item.name === ob.name) {
return true;
}
});
return false;
}

Returning inside a forEach callback has no effect - isContains will always return false. Better to use an object or Map indexed by the name instead, to reduce computational complexity by an order of magnitude - then you can get that object's values to get the array you want:
const items=[{discount:27.6,name:"Floy Vandervort",price:230,quantity:3,taxable:662.4},{discount:122.88,name:"Adriel Abshire II",price:256,quantity:6,taxable:1413.12},{discount:159.66,name:"Tabitha Stroman",price:887,quantity:2,taxable:1614.34},{discount:27.6,name:"Floy Vandervort",price:230,quantity:3,taxable:662.4},{discount:122.88,name:"Adriel Abshire II",price:256,quantity:6,taxable:1413.12},{discount:159.66,name:"Tabitha Stroman",price:887,quantity:2,taxable:1614.34},{discount:27.6,name:"Floy Vandervort",price:230,quantity:3,taxable:662.4},{discount:122.88,name:"Adriel Abshire II",price:256,quantity:6,taxable:1413.12},{discount:159.66,name:"Tabitha Stroman",price:887,quantity:2,taxable:1614.34}];
function squish(items) {
const squishedItemsByName = items.reduce((a, { name, ...props }) => {
if (!a[name]) {
a[name] = { name };
}
Object.entries(props).forEach(([prop, val]) => {
a[name][prop] = (a[name][prop] || 0) + val;
});
return a;
}, {});
return Object.values(squishedItemsByName);
}
console.log(squish(items));

Try
let h = {};
items.forEach(x=> h[x.name]= !h[x.name] ? x : {
discount: h[x.name].discount+x.discount,
name: x.name,
price: x.price,
quantity: h[x.name].quantity+x.quantity,
taxable: h[x.name].taxable+x.taxable
});
let result = Object.keys(h).map(k=> h[k]);
items= [
{
discount: 27.6,
name: 'Floy Vandervort',
price: 230,
quantity: 3,
taxable: 662.4
},
{
discount: 122.88,
name: 'Adriel Abshire II',
price: 256,
quantity: 6,
taxable: 1413.12
},
{
discount: 159.66,
name: 'Tabitha Stroman',
price: 887,
quantity: 2,
taxable: 1614.34
},
{
discount: 27.6,
name: 'Floy Vandervort',
price: 230,
quantity: 3,
taxable: 662.4
},
{
discount: 122.88,
name: 'Adriel Abshire II',
price: 256,
quantity: 6,
taxable: 1413.12
},
{
discount: 159.66,
name: 'Tabitha Stroman',
price: 887,
quantity: 2,
taxable: 1614.34
},
{
discount: 27.6,
name: 'Floy Vandervort',
price: 230,
quantity: 3,
taxable: 662.4
},
{
discount: 122.88,
name: 'Adriel Abshire II',
price: 256,
quantity: 6,
taxable: 1413.12
},
{
discount: 159.66,
name: 'Tabitha Stroman',
price: 887,
quantity: 2,
taxable: 1614.34
}
]
let h = {};
items.forEach(x=> h[x.name]= !h[x.name] ? x : {
discount: h[x.name].discount+x.discount,
name: x.name,
price: x.price,
quantity: h[x.name].quantity+x.quantity,
taxable: h[x.name].taxable+x.taxable
});
let result = Object.keys(h).map(k=> h[k]);
console.log(result);

One of many ways of doing this could be the following :
const uniqueItems = Object.values(
items.reduce((hashMap, item) => {
if (!hashMap[item.name]) {
hashMap[item.name] = { ...item };
} else {
// You should use a safest way to add
hashMap[item.name].discount += item.discount;
hashMap[item.name].price += item.price;
hashMap[item.name].quantity += item.quantity;
hashMap[item.name].taxable += item.taxable;
}
return hashMap;
}, {})
)

Related

Question from a beginner: Unexpected JS behavior [duplicate]

I'm trying to convert an array of objects where i return duplicated objects if the object properties quantity is greater than 1.
const objects = [
{ id: 1, name: "Scissor", price: 2, quantity: 3 },
{ id: 2, name: "Hat", price: 6.5, quantity: 1 },
{ id: 3, name: "Socks", price: 0.5, quantity: 5 },
];
// desired return
[
{ id: 1, name: "Scissor", price: 2 }
{ id: 1, name: "Scissor", price: 2 }
{ id: 1, name: "Scissor", price: 2 }
{ id: 2, name: "Hat", price: 6.5}
{ id: 3, name: "Socks", price: 0.5 }
{ id: 3, name: "Socks", price: 0.5 }
{ id: 3, name: "Socks", price: 0.5 }
{ id: 3, name: "Socks", price: 0.5 }
{ id: 3, name: "Socks", price: 0.5 }
]
My code:
const objects = [
{ id: 1, name: "Scissor", price: 2, quantity: 3 },
{ id: 2, name: "Hat", price: 6.5, quantity: 1 },
{ id: 3, name: "Socks", price: 0.5, quantity: 5 },
];
let newObjects= [];
Object.entries(objects).forEach(([key, value]) => {
for (let i=0; i < value.quantity; i++){
newObjects.push({ id: value.id, name: value.name, price: value.price})
}
});
console.log(newObjects);
So my code above does work, does return what i wanted, however i feel like there is a better/smoother and more of ES6 and beyond method. Could anyone please suggest a better way?
You could use .fill() and .flatMap().
const objects = [
{ id: 1, name: "Scissor", price: 2, quantity: 3 },
{ id: 2, name: "Hat", price: 6.5, quantity: 1 },
{ id: 3, name: "Socks", price: 0.5, quantity: 5 },
];
let newObjects = objects.flatMap(e=>
Array(e.quantity).fill({id: e.id, name: e.name, price: e.price})
);
console.log(newObjects);
You can use an array reduce along with an array fill.
The map is required only if you want to have unique references otherwise you can fill using the same object.
const objects = [
{ id: 1, name: "Scissor", price: 2, quantity: 3 },
{ id: 2, name: "Hat", price: 6.5, quantity: 1 },
{ id: 3, name: "Socks", price: 0.5, quantity: 5 },
];
const output = objects.reduce((a, c) => {
return a.concat(Array(c.quantity).fill({}).map(x=>({
id: c.id,
name: c.name,
price: c.price
})))
}, []);
console.log(output)

How would I prevent duplicates in array of objects? And if there is a object with same property, it should sume its value

So basically what I am trying to achieve is.. I have an array with objects, in my case array of items in stock. And when I add item to cart array, it should check if an object with the same property (name) already exists. And if it exists, it should just sum the count of them. So that I don't have duplicates... But it sums the count.
const stock = [
{
id: 0,
name: 'Leaf Blower',
price: 250,
stock: 24,
count: 0,
logoURL: process.env.PUBLIC_URL + '/images/1.png',
},
{
id: 1,
name: 'Generator',
price: 1299,
stock: 12,
count: 0,
logoURL: process.env.PUBLIC_URL + '/images/2.png',
},
{
id: 2,
name: 'Log Splitter',
price: 2133,
stock: 5,
count: 0,
logoURL: process.env.PUBLIC_URL + '/images/3.png',
},
{
id: 3,
name: 'Lawn Mower',
price: 250,
stock: 24,
count: 0,
logoURL: process.env.PUBLIC_URL + '/images/4.png',
},
{
id: 4,
name: 'Chainsaw',
price: 344,
stock: 16,
count: 0,
logoURL: process.env.PUBLIC_URL + '/images/5.png',
},
];
This:
const shoppingCart = [
{
id: 0,
name: 'Leaf Blower',
price: 250,
stock: 24,
count: 5,
logoURL: process.env.PUBLIC_URL + '/images/1.png',
},
id: 0,
name: 'Leaf Blower',
price: 250,
stock: 24,
count: 3,
logoURL: process.env.PUBLIC_URL + '/images/1.png',
}
]
Should be:
const shoppingCart = [
{
id: 0,
name: 'Leaf Blower',
price: 250,
stock: 24,
count: 8,
logoURL: process.env.PUBLIC_URL + '/images/1.png',
}
]
You can check if the objectToBeAdded is already there in the shoppingCart. And then update shoppingCart accordingly.
const indexOfObject = shoppingCart.findIndex(item => item.name === objectToBeAdded.name);
if(indexOfObject > -1) {
shoppingCart[indexOfObject].count += objectToBeAdded.count;
} else {
shoppingCart = [...shoppingCart, objectToBeAdded];
}
You can do this by using array reduce method. Just traverse the array and sum the count property.
const shoppingCart = [
{
id: 0,
name: 'Leaf Blower',
price: 250,
stock: 24,
count: 5,
logoURL: `process.env.PUBLIC_URL + '/images/1.png`,
},
{
id: 0,
name: 'Leaf Blower',
price: 250,
stock: 24,
count: 3,
logoURL: `process.env.PUBLIC_URL + '/images/1.png`,
},
];
let ret = shoppingCart.reduce((prev, c) => {
const p = prev;
if (!p[c.id]) p[c.id] = { ...c };
else p[c.id] = { ...c, count: c.count + p[c.id].count };
return p;
}, {});
ret = Object.values(ret);
console.log(ret);
Something like this should work:
if (!shoppingCart.find(element => element.name == objectToBeAdded.name)) {shoppingCart.push(objectToBeAdded)}
Here, you use Array.find() to check if there is an object with a matching name in the array. If not, you add the object to array.

ES6: Populate object value with a value from another object when ID is present

I would like to populate the value 'discount' for a product with the discount ID value from the array discounts, if the respective product ID exists as a value in the Discounts object.
const products = [{
id: "05cdb75d-7984-4dbf-b0f4-d6532163b66d",
name: "SANTO - Schnürstiefelette",
price: 199.95,
discount: 0,
},
{
id: "1b9b6c7e-c856-464c-ba64-98c9dd6733b5",
name: "AIR FORCE 1 07 LV8 - Sneaker low",
price: 109.95,
discount: 0,
},
{
id: "f831aaf4-347a-458f-bb0c-21cf02aeac2e",
name: "DUFF 9.0 - Sporttasche",
price: 34.95,
discount: 0,
},
{
id: "471ad894-150b-4a2b-881c-a9a4dbc4b401",
name: "Strickpullover",
price: 20.99,
discount: 0,
},
];
const discounts = [{
id: "5791ae04-a704-4f44-808b-de5ddb8812b5",
name: "Christmas discount",
productIds: ["1b9b6c7e-c856-464c-ba64-98c9dd6733b5", "f831aaf4-347a-458f-bb0c-21cf02aeac2e"],
active: true
},
{
id: "5791ae04-a704-4f44-808b-de5ddb8812e6",
name: "Christmas discount 2",
productIds: ["05cdb75d-7984-4dbf-b0f4-d6532163b66d"],
active: true
}
];
At the end i need it like:
const products = [{
id: "05cdb75d-7984-4dbf-b0f4-d6532163b66d",
name: "SANTO - Schnürstiefelette",
price: 199.95,
discount: '5791ae04-a704-4f44-808b-de5ddb8812e6',
},
...
...
You could use map() to transform products array. And find() and includes() to check if discount exists for a product.
const products = [{ id: "05cdb75d-7984-4dbf-b0f4-d6532163b66d", name: "SANTO - Schnürstiefelette", price: 199.95, discount: 0, }, { id: "1b9b6c7e-c856-464c-ba64-98c9dd6733b5", name: "AIR FORCE 1 07 LV8 - Sneaker low", price: 109.95, discount: 0, }, { id: "f831aaf4-347a-458f-bb0c-21cf02aeac2e", name: "DUFF 9.0 - Sporttasche", price: 34.95, discount: 0, }, { id: "471ad894-150b-4a2b-881c-a9a4dbc4b401", name: "Strickpullover", price: 20.99, discount: 0, }, ];
const discounts = [{ id: "5791ae04-a704-4f44-808b-de5ddb8812b5", name: "Christmas discount", productIds: ["1b9b6c7e-c856-464c-ba64-98c9dd6733b5", "f831aaf4-347a-458f-bb0c-21cf02aeac2e"], active: true }, { id: "5791ae04-a704-4f44-808b-de5ddb8812e6", name: "Christmas discount 2", productIds: ["05cdb75d-7984-4dbf-b0f4-d6532163b66d"], active: true } ];
let result = products.map(product => {
let discount = discounts.find(item => item.productIds.includes(product.id));
return {
...product,
"discount": discount ? discount.id : product.discount
};
});
console.log(result);
You could store the discounts in a Map and map the object with a new discount object, if necessary.
var products = [{ id: "05cdb75d-7984-4dbf-b0f4-d6532163b66d", name: "SANTO - Schnürstiefelette", price: 199.95, discount: 0 }, { id: "1b9b6c7e-c856-464c-ba64-98c9dd6733b5", name: "AIR FORCE 1 07 LV8 - Sneaker low", price: 109.95, discount: 0 }, { id: "f831aaf4-347a-458f-bb0c-21cf02aeac2e", name: "DUFF 9.0 - Sporttasche", price: 34.95, discount: 0 }, { id: "471ad894-150b-4a2b-881c-a9a4dbc4b401", name: "Strickpullover", price: 20.99, discount: 0 }],
discounts = [{ id: "5791ae04-a704-4f44-808b-de5ddb8812b5", name: "Christmas discount", productIds: ["1b9b6c7e-c856-464c-ba64-98c9dd6733b5", "f831aaf4-347a-458f-bb0c-21cf02aeac2e"], active: true }, { id: "5791ae04-a704-4f44-808b-de5ddb8812e6", name: "Christmas discount 2", productIds: ["05cdb75d-7984-4dbf-b0f4-d6532163b66d"], active: true }],
ids = discounts.reduce((m, { id, productIds }) => productIds.reduce((n, pid) => n.set(pid, id), m), new Map);
products = products.map(p => Object.assign({}, p, ids.has(p.id) && { discount: ids.get(p.id) }));
console.log(products);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nested loop through both products and discounts array, if the product id is included inside the productIds array of any of the objects in the discounts array, assign the discount id to the product discount.
for (let product of products) {
for (let discount of discounts) {
if (discount.productIds.includes(product.id)){
product.discount = discount.id;
break;
}
}
}

How to sum multiple different objects in an array using Vuejs?

I am getting started with Vue. I am struggling to calculate the sum of different elements in an object of an array.
My array looks like this:
sites: [{
sku: 10001,
name: "Product A",
totalPrice: '',
values: [{
price: 10,
discount: 5,
color: "red"
},
{
price: 15,
discount: 8,
color: "black"
}]
},
{
sku: 10002,
name: "Product B",
totalPrice: '',
values: [{
price: 13,
discount: 3,
color: "purple"
},
{
price: 20,
discount: 5,
color: "green"
}]
}]
I am trying to sum the price and set it to totalPrice. So the array will change totalPrice as below:
sku: 10001,
name: "Product A",
totalPrice: 25,
sku: 10002,
name: "Product B",
totalPrice: 33,
I believe I need to use something like the below to sum them, however I cannot figure out how to do this!
computed: {
total(){ return this.sites.reduce( (total, item) => item.values. price + total ,0);}
},
How do I calculate the sum of the price and set it as the totalPrice?
I have traveled SO and find similar threads however nothing that I can get to work with my issue.
computed: {
total() {
let newojv = []
sites.forEach((item, _) => {
let s = item.values.map((items2, _) => {
return items2.price;
})
let sum = s.reduce((a, b) => a + b);
newojv.push({
sku: item.sku,
name: item.name,
totalPrice: sum
});
});
return newojv;
}
}
First for Each of the array of objects below
{
sku: 10001,
name: "Product A",
totalPrice: '',
values: [{
price: 10,
discount: 5,
color: "red"
},
{
price: 15,
discount: 8,
color: "black"
}
]
}
And then for Each of the array of objects below
values: [{
price: 10,
discount: 5,
color: "red"
},
{
price: 15,
discount: 8,
color: "black"
}
]
We take a we map the array to get the values of the price, which is 10,15. Then we reduce the array, add it and then push it.
let sum = s.reduce((a, b) => a + b);
newojv.push({
sku: item.sku,
name: item.name,
totalPrice: sum
});
A working example can be
let sites = [{
sku: 10001,
name: "Product A",
totalPrice: '',
values: [{
price: 10,
discount: 5,
color: "red"
},
{
price: 15,
discount: 8,
color: "black"
}
]
}, {
sku: 10002,
name: "Product B",
totalPrice: '',
values: [{
price: 13,
discount: 3,
color: "purple"
},
{
price: 20,
discount: 5,
color: "green"
}
]
}]
let newojv = []
sites.forEach((item, _) => {
let s = item.values.map((items2, _) => {
return items2.price;
})
let sum = s.reduce((a, b) => a + b);
newojv.push({
sku: item.sku,
name: item.name,
totalPrice: sum
});
});
console.log(newojv)

Filter and combine fields from 2 arrays with ES6 JavaScript?

I have 2 arrays, one of pizza details and the other is an order state. The id field is what links them. So in this example, the order has 2 x Pepperoni and 3 x Margarita.
const pizzaContent = [
{
id: 0,
name: 'Pepperoni',
price: 20,
hot: true,
stockQuantity: 3
},
{
id: 1,
name: 'Margarita',
price: 25,
stockQuantity: 3
},
{
id: 2,
name: 'Hawaiian',
price: 15,
stockQuantity: 0
}
];
const orders = [{
id: 0,
quantity: 2
},{
id: 1,
quantity: 3
}];
I'm trying to create a new array which has the quantity from orders and the fields from pizzaContent. Any pizzas which aren't in the order shouldn't be part of this array.
I've gotten close with the following:
const pizzasInOrder = this.props.orders.map(order => {
return (
{
quantity: order.quantity,
pizza: this.props.pizzas.find(pizza => {
return (
order.id === pizza.id
);
})
}
)
});
However, the result is:
pizzasInOrder = [
{
pizza: {id: 0, name: "Pepperoni", price: 20, hot: true, stockQuantity: 3},
quantity:2
},
{
pizza: {id: 1, name: "Margarita", price: 25, stockQuantity: 3},
quantity:3
}
]
But what I need is:
pizzasInOrder = [
{
id: 0, name: "Pepperoni", price: 20, hot: true, stockQuantity: 3, quantity: 2
},
{
id: 1, name: "Margarita", price: 25, stockQuantity: 3, quantity: 3
}
]
Use Object.assign and no extra keys
const pizzasInOrder = this.props.orders.map(order =>
Object.assign({quantity: order.quantity},
this.props.pizzas.find(pizza => order.id === pizza.id))
);
You can use Object.assign() to merge objects into one.
example..
const pizzaContent = [
{
id: 0,
name: 'Peperoni',
price: 20,
hot: true,
stockQuantity: 3
},
{
id: 1,
name: 'Margarita',
price: 25,
stockQuantity: 3
},
{
id: 2,
name: 'Hawian',
price: 15,
stockQuantity: 0
}
];
const orders = [{
id: 0,
quantity: 2
},{
id: 1,
quantity: 3
}];
let pizzasInOrder = orders.map((order) => {
return Object.assign(order,
pizzaContent.find(pizza => order.id === pizza.id));
});
console.log(pizzasInOrder);

Categories