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

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.

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)

Count Unique Value from Two object of array in Javascript

Given an array of categories and an array of entries, creates an array of objects with a category name and an entry count. Consider id is equal to categoryId.
var categories = [
{ name: 'Cats', id: 10 },
{ name: 'Dogs', id: 20 },
];
var entries = [
{categoryId: 10, name: 'Fluffy'},
{categoryId: 10, name: 'Spot'},
{categoryId: 10, name: 'Lil'},
{categoryId: 20, name: 'Tom'},
{categoryId: 20, name: 'Buck'},
{categoryId: 20, name: 'Flo'},
{categoryId: 20, name: 'Cheek'},
{categoryId: 10, name: 'Stan'},
{categoryId: 20, name: 'Stila'}
]
Expected Output: [{ name:'Cats', count: 4 }, { name:'Dogs', count: 5 }];
I wrote it like this below, but there seem to be a performance problem when you try to run it through hundreds of categories and tens of thousands of entries.
const categoriesByEntryCount = (categories, entries) =>
categories.map(category => ({
name: category.name,
count: entries.filter(entry => entry.categoryId === category.id).length,
}));
My question is there another way to write or implement this ?
You need to use Maps in all possible places.
var categories = new Map();
categories.set(10, 'Cats');
categories.set(20, 'Dogs');
var entries = [
{ categoryId: 10, name: 'Fluffy' },
{ categoryId: 10, name: 'Spot' },
{ categoryId: 10, name: 'Lil' },
{ categoryId: 20, name: 'Tom' },
{ categoryId: 20, name: 'Buck' },
{ categoryId: 20, name: 'Flo' },
{ categoryId: 20, name: 'Cheek' },
{ categoryId: 10, name: 'Stan' },
{ categoryId: 20, name: 'Stila' },
];
console.log(Array.from(
entries.reduce(
(m, { categoryId, name }) =>
m.set(categoryId, (m.get(categoryId) || 1) + 1),
new Map()
),
([k, v]) => ({ name: categories.get(k), count: v })
));
const categories = [ { name: 'Cats', id: 10 }, { name: 'Dogs', id: 20 } ];
const entries = [ { categoryId: 10, name: 'Fluffy' }, { categoryId: 10, name: 'Spot' }, { categoryId: 10, name: 'Lil' }, { categoryId: 20, name: 'Tom' }, { categoryId: 20, name: 'Buck' }, { categoryId: 20, name: 'Flo' }, { categoryId: 20, name: 'Cheek' }, { categoryId: 10, name: 'Stan' }, { categoryId: 20, name: 'Stila' } ];
// get number of occurences of each category in entries
const categoriesCount = entries.reduce((countMap, { categoryId }) =>
countMap.set( categoryId, 1 + (countMap.get(categoryId) || 0) )
, new Map);
// iterate over categories and return name and count in categoriesCount
const res = categories.map(({ name, id }) =>
({ name, count: categoriesCount.get(id) })
);
console.log(res);
We can do like below with time complexity O(M + N)
var categories = [
{ name: 'Cats', id: 10 },
{ name: 'Dogs', id: 20 },
];
var entries = [
{categoryId: 10, name: 'Fluffy'},
{categoryId: 10, name: 'Spot'},
{categoryId: 10, name: 'Lil'},
{categoryId: 20, name: 'Tom'},
{categoryId: 20, name: 'Buck'},
{categoryId: 20, name: 'Flo'},
{categoryId: 20, name: 'Cheek'},
{categoryId: 10, name: 'Stan'},
{categoryId: 20, name: 'Stila'}
]
const categoriesByEntryCount = (categories, entries) => {
const entriesHash = entries.reduce((acc, ele) => {
acc[ele.categoryId] = acc[ele.categoryId] ? acc[ele.categoryId] + 1 : 1;
return acc;
}, {});
return categories.map(category => ({
name: category.name,
count: entriesHash[category.id],
}));
}
console.log(categoriesByEntryCount(categories, entries))
This is obviously a reducing job.
var categories = [ { name: 'Cats', id: 10 }
, { name: 'Dogs', id: 20 }
],
entries = [ {categoryId: 10, name: 'Fluffy'}
, {categoryId: 10, name: 'Spot'}
, {categoryId: 10, name: 'Lil'}
, {categoryId: 20, name: 'Tom'}
, {categoryId: 20, name: 'Buck'}
, {categoryId: 20, name: 'Flo'}
, {categoryId: 20, name: 'Cheek'}
, {categoryId: 10, name: 'Stan'}
, {categoryId: 20, name: 'Stila'}
],
result = entries.reduce((cs,e) => ( cs.map(c => c.id === e.categoryId ? c.count ? c.count++
: c.count = 1
: c)
, cs
), categories);
console.log(result);
You may complain that the result includes the id property but that's just good.

Merge Object preserving it's value using addition in 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;
}, {})
)

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