Question from a beginner: Unexpected JS behavior [duplicate] - javascript

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)

Related

How to groupBy with sum using lodash

I have productId which is an array of values.
const groupByvalue= [1, 2];
I have products that have multiple product arrays.
const products = [
{
id: 1,
name: 'milk',
qty: 2
},
{
id: 2,
name: 'butter',
qty: 2
},
{
id: 3,
name: 'milk',
qty: 2
},
{
id: 2,
name: 'butter',
qty: 2
},
{
id: 1,
name: 'milk',
qty: 2
},
{
id: 3,
name: 'butter',
qty: 2
},
{
id: 1,
name: 'milk',
qty: 2
},
{
id: 3,
name: 'butter',
qty: 2
}
];
const groupByKey = 'id';
I need to group the products based on the product's id.
conditions
i)groupBy should be based on the groupByvalue with groupBykey array (only groupBy 1 , 2)
ii) after the group it should sum all the qty
expected
[
{
id: 1,
name : "milk",
qty : sum of all qty
},
{
id: 2,
name : "butter",
qty : sum of all qty
}
];
Thanks!!
Using Lodash
var _ = require('lodash');
var groupByValue = [1, 2];
var groupByKey = 'id';
const products = [
{ id: 1, name: 'milk', qty: 2 },
{ id: 2, name: 'butter', qty: 2 },
{ id: 3, name: 'milk', qty: 2 },
{ id: 2, name: 'butter', qty: 2 },
{ id: 1, name: 'milk', qty: 2 },
{ id: 3, name: 'butter', qty: 2 },
{ id: 1, name: 'milk', qty: 2 },
{ id: 3, name: 'butter', qty: 2 }
]
const ans = _(products)
.groupBy(groupByKey)
.map((product) => {
if(groupByValue.includes(product[0].id)){
return {
id: product[0].id,
name: product[0].name,
qty: _.sumBy(product, 'qty')
}
}
})
.value()
console.log(ans.filter(item => item));
Output :-
[ { id: 1, name: 'milk', qty: 6 }, { id: 2, name: 'butter', qty: 4 } ]
No need for lodash whatsoever, this is a native .reduce() task. You may do like;
var groupByValue = [1, 2],
groupByKey = 'id',
products = [ { id : 1
, name: 'milk'
, qty : 2
}
, { id : 2
, name: 'butter'
, qty : 2
}
, { id : 3
, name: 'milk'
, qty: 2
}
, { id : 2
, name: 'butter'
, qty : 2
}
, { id : 1
, name: 'milk'
, qty : 2
}
, { id : 3
, name: 'butter'
, qty : 2
}
, { id : 1
, name: 'milk'
, qty : 2
}
, { id : 3
, name: 'butter'
, qty : 2
}
],
interim = products.reduce( (r,p) => ( groupByValue.includes(p[groupByKey]) && (r[p[groupByKey]] ? r[p[groupByKey]].qty += p.qty
: r[p[groupByKey]] = Object.assign({},p))
, r
)
, {}
),
result = Object.values(interim);
console.log(result);
The milk products with id:3 doesn't count.
I would filter the array first, and then make the map,
this can be done in single .reduce(...) function, but its more readable using lodash:
const _ = require('lodash');
const groupByValue = [1, 2];
const groupByKey = 'id';
const products = [
{ id: 1, name: 'milk', qty: 1 },
{ id: 2, name: 'butter', qty: 2 },
{ id: 3, name: 'cheese', qty: 4 },
{ id: 2, name: 'butter', qty: 5 },
{ id: 1, name: 'milk', qty: 3 },
{ id: 3, name: 'cheese', qty: 6 },
{ id: 1, name: 'milk', qty: 1 },
{ id: 3, name: 'cheese', qty: 7 }
];
const result = _(products)
.filter(itm => groupByValue.includes(itm.id))
.groupBy(groupByKey)
.map(arr => {
const { id, name } = arr[0];
return { id, name, qty: _(arr).sumBy('qty') };
})
.value();
console.log(result);
// output: [{ id: 1, name: 'milk', qty: 5},{id: 2, name: 'butter', qty: 7}]

How to first combine properties of an object then remove the duplicates in an array of objects using Javascript

I have an array of objects here:
const arr = [
{ id: 1, name: "test1", quantity:1 },
{ id: 2, name: "test2", quantity:1 },
{ id: 2, name: "test3", quantity:1 },
{ id: 3, name: "test4", quantity:1 },
{ id: 4, name: "test5", quantity:1 },
{ id: 5, name: "test6", quantity:1 },
{ id: 5, name: "test7", quantity:1 },
{ id: 6, name: "test8", quantity:1 }
];
I want to add quantities of the duplicate objects together before removing them
So the result is:
const arr = [
{ id: 1, name: "test1", quantity:1 },
{ id: 2, name: "test3", quantity:2 },
{ id: 3, name: "test4", quantity:1 },
{ id: 4, name: "test5", quantity:1 },
{ id: 5, name: "test6", quantity:2 },
{ id: 6, name: "test8", quantity:1 }
];
I have seen variations of it done removing duplicates using map or reduce but I haven't seen anything that can what I want to accomplish in an eloquent way without using too many loops.
I have been thinking about how to best accomplish this all day and haven't found anything, any help would be appreciated
You can use reduce with an object to store the element with each id.
const arr = [
{ id: 1, name: "test1", quantity:1 },
{ id: 2, name: "test2", quantity:1 },
{ id: 2, name: "test3", quantity:1 },
{ id: 3, name: "test4", quantity:1 },
{ id: 4, name: "test5", quantity:1 },
{ id: 5, name: "test6", quantity:1 },
{ id: 5, name: "test7", quantity:1 },
{ id: 6, name: "test8", quantity:1 }
];
const res = Object.values(
arr.reduce((acc,curr)=>{
acc[curr.id] = acc[curr.id] || {...curr, quantity: 0};
acc[curr.id].quantity += curr.quantity;
return acc;
}, {})
);
console.log(res);
const arr = [
{ id: 1, name: "test1", quantity: 1 },
{ id: 2, name: "test2", quantity: 1 },
{ id: 2, name: "test3", quantity: 1 },
{ id: 3, name: "test4", quantity: 1 },
{ id: 4, name: "test5", quantity: 1 },
{ id: 5, name: "test6", quantity: 1 },
{ id: 5, name: "test7", quantity: 1 },
{ id: 6, name: "test8", quantity: 1 }
];
var result = arr.reduce(function (r, a) {
r[a.id] = r[a.id] || { id: a.id, quantity: 0, name: a.name };
r[a.id].quantity += a.quantity;
return r;
}, Object.create(null));
console.log(JSON.stringify(result));
Using forEach loop and build object with aggregated quantity count.
const convert = (arr) => {
const res = {};
arr.forEach(({ id, ...rest }) =>
res[id] ? (res[id].quantity += 1) : (res[id] = { id, ...rest })
);
return Object.values(res);
};
const arr = [
{ id: 1, name: "test1", quantity: 1 },
{ id: 2, name: "test2", quantity: 1 },
{ id: 2, name: "test3", quantity: 1 },
{ id: 3, name: "test4", quantity: 1 },
{ id: 4, name: "test5", quantity: 1 },
{ id: 5, name: "test6", quantity: 1 },
{ id: 5, name: "test7", quantity: 1 },
{ id: 6, name: "test8", quantity: 1 },
];
console.log(convert(arr));

return specific properties from array of objects into new object [duplicate]

This question already has answers here:
From an array of objects, extract value of a property as array
(24 answers)
Closed 2 years ago.
I've an array of objects, what I want is to copy all the objects from that, but with specific properties not all the properties.
like for example I've this object named cart
cart = [
{ id: 1, name: 'makeup', price: 200, qty: 1 },
{ id: 2, name: 'gloves', price: 300, qty: 2 },
{ id: 3, name: 'sanitizer', price: 400, qty: 3 },
{ id: 4, name: 'book', price: 100, qty: 1 },
{ id: 5, name: 'hairs', price: 250, qty: 4 },
{ id: 6, name: 'soap', price: 50, qty: 5 },
{ id: 7, name: 'shampoo', price: 700, qty: 1 },
]
and I want to extract only the id and qty attributes to a new array of objects.
How do I do this.
I already tried
products=cart.map(prod=>prod.id, prod.qty)
but this doesn't seems to be working.
Thanks in advance to helping hands
You can Array.prototype.map() or Array.prototype.reduce() over the entire array and only return the values you want.
const cart = [
{ id: 1, name: 'makeup', price: 200, qty: 1 },
{ id: 2, name: 'gloves', price: 300, qty: 2 },
{ id: 3, name: 'sanitizer', price: 400, qty: 3 },
{ id: 4, name: 'book', price: 100, qty: 1 },
{ id: 5, name: 'hairs', price: 250, qty: 4 },
{ id: 6, name: 'soap', price: 50, qty: 5 },
{ id: 7, name: 'shampoo', price: 700, qty: 1 },
]
console.log( cart.map( elem => ({id:elem.id, qty : elem.qty})))
You need to iterate and return only the desired properties.
cart = [
{ id: 1, name: 'makeup', price: 200, qty: 1 },
{ id: 2, name: 'gloves', price: 300, qty: 2 },
{ id: 3, name: 'sanitizer', price: 400, qty: 3 },
{ id: 4, name: 'book', price: 100, qty: 1 },
{ id: 5, name: 'hairs', price: 250, qty: 4 },
{ id: 6, name: 'soap', price: 50, qty: 5 },
{ id: 7, name: 'shampoo', price: 700, qty: 1 },
]
const newcart = cart.map(item => {
return {id: item.id, qty: item.qty}
});
console.log(newcart)
You almost had it correct.
When using arrow functions without the brackets, whatever is put after the arrow function is returned.
So your code could look like this:
const products = cart.map(({ id, qty }) => ({ id, qty }));
We destructure the object in the arrow function and return it as a new object.
Make sure to have the round brackets around the value that you return. Otherwise javascript will see it as the body of a function instead of an object that is returned.
You can update your .map() method like this to acheive the desired result:
const cart = [{id:1,name:"makeup",price:200,qty:1},{id:2,name:"gloves",price:300,qty:2},{id:3,name:"sanitizer",price:400,qty:3},{id:4,name:"book",price:100,qty:1},{id:5,name:"hairs",price:250,qty:4},{id:6,name:"soap",price:50,qty:5},{id:7,name:"shampoo",price:700,qty:1}];
const products = cart.map(({id, qty}) => ({ id, quantity: qty }))
console.log(products)
.as-console-wrapper { max-height: 100% !important; top: 0; }

Moving data from 2 arrays of objects into a third array

so assume i have 2 arrays of objects...
let orders = [
{ id: 1, itemName: 'Peaches', amount: 2 },
{ id: 2, itemName: 'Mangoes', amount: 1 },
{ id: 3, itemName: 'Mangoes', amount: 10 }
];
let items = [
{ id: 1, name: 'Peaches', qty: 10 },
{ id: 2, name: 'Mangoes', qty: 3 }
];
and i want to find the list of orders for every item and put them in an array called linkedOrders, I tried the below code:
let linkedOrders = _.map(items, item => _.where(orders, { name: item.name }));
console.log(linkedOrders);
This is what I am getting:
[{ id: 1, itemName: 'Peaches', amount: 2 }],
[{ id: 2, itemName: 'Mangoes', amount: 1 },
{ id: 3, itemName: 'Mangoes', amount: 10 }]
but I want something like this:
[{'Peaches': [
{ id: 1, itemName: 'Peaches', amount: 2 }
],
'Mangoes': [
{ id: 2, itemName: 'Mangoes', amount: 1 },
{ id: 3, itemName: 'Mangoes', amount: 10 }
]],
Any help would be appreciated thanks.
You can simply do that using Array reduce method.
const result = items.reduce((result, item) => {
result.push({
[item.name]: orders.filter((order) => order.itemName === item.name)
});
return result;
}, []);
For more information on reduce, check Array​.prototype​.reduce()

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