How to get min values among properties inside an array of objects? - javascript

In React I have an object like:
shirt : {
title : "Abc",
material : "cotton",
options : [
0 : {
price: 10,
color: red
},
1 : {
price: 20,
color: green
},
2 : {
price: 30,
color: blue
},
}
In the catalog page I want to display only the cheapest option ("From $10") for every shirt.
To display all shirts I use map function:
shirts.map((shirt) => (<div>{shirt.title}</div><div>{shirt.material}</div>))
How can I show only the cheapest price?
I can not use {shirt.options.price[0]} because the first element of the array is not always the cheapest price.

You could do:
const minPrice = Math.min(...shirt.options.map(({price}) => price))
const cheapeastShirt = shirt.options.find({price} => minPrice === price)

Related

Use of ternary operator inside filter and map method in javascript?

I have an cart object. I want to change the qty of a product in cart for which i have created a changeQty method inside which I am using filter method to find the respective product and then I am updating the qty.
If I pass other than 0 it works properly. But if I pass 0 as quantity to the changeQty method the product get's removed from the cart.
According to my knowledge filter works based on the return value. But here I am assigning qty to product.qty. And also If I use map instead of filter I am geting 0 in place of that product. So my doubt is what does product.qty = qty returns ?
let cart = [{
id: 1,
title: "Product 1",
qty: 1
},
{
id: 2,
title: "Product 2",
qty: 1
},
]
const changeQty = (pid, qty) => {
cart = cart.filter(product => product.id === pid ? product.qty = qty : product)
console.log(cart);
}
changeQty(1, 0)
Use map instead of filter. You can use spread syntax and overwrite the value of qty for the product that matches the id.
let cart = [{
id: 1,
title: "Product 1",
qty: 1
},
{
id: 2,
title: "Product 2",
qty: 1
},
]
const changeQty = (pid, qty) => {
cart = cart.map(product => product.id === pid ? { ...product, qty } : product)
console.log(cart);
}
changeQty(1, 0)
if I pass 0 as quantity to the changeQty method the product get's removed from the cart.
That's because the assignment of 0 to product.qty evaluates to a 0 return value for the filter callback. That is a falsy value, indicating the current cart item should be filtered out. In fact, you don't want to filter at all. On the contrary, you don't want to change the length of the cart array.
If your goal is to mutate the cart structure, then possibly you are looking for find instead of filter:
const cart = [{id:1,title:"Product 1",qty:1},{id:2,title:"Product 2",qty:1}];
const changeQty = (pid, qty) => {
Object(cart.find(({id}) => id === pid)).qty = qty;
console.log(cart);
}
changeQty(1, 0);
NB: the call to Object is to deal silently with a product that is not in the cart.
You are modifying the source object which is very bad:
let cart = [{
id: 1,
title: "Product 1",
qty: 1
},
{
id: 2,
title: "Product 2",
qty: 1
},
]
const changeQty = (pid, qty) => {
cart.forEach(product => product.id === pid ? product.qty = qty : product)
console.log(cart);
}
changeQty(1, 0)
That's why you are getting unexpected results
Or you can do it with this one-liner:
let cart = [{id: 1,title: "Product 1",qty: 1},{id: 2,title: "Product 2",qty: 1}];
const changeQty = (pid, qty) =>( cart.forEach(p => p.id===pid && (p.qty=qty)), cart );
console.log(changeQty(1, 0));
As OP's intention was to change the input array cart the .forEach() methods presents itself as a suitable candidate.
I don't know how many cart items there might be with your p.id===pid. In my snippet they would all be changed by getting an updated qty property. Trincot provides an array.find() based solution that is probably more performant but will only affect the first cart item matching the specified pid.

Javascript Sort Array of objects by object property that exists in several objects [duplicate]

This question already has answers here:
Sort an array of object by a property (with custom order, not alphabetically)
(7 answers)
Closed last year.
I have an array of products where several products can have the same color, and i want to be able to sort this array by the color value. How i would i achieve an Array sorting for example to display all products first that has the color property of "red"? Or any other color that i will tell the array to sort first by.
const arr = [
{
name: "T-shirt",
color: "red",
price: 20
},
{
name: "Shoes",
color: "yellow",
price: 20
},
{
name: "Pants",
color: "red",
price: 20
},
{
name: "Cap",
color: "yellow",
price: 20
},
{
name: "Skirt",
color: "red",
price: 15
},
]
Like this you will sort your array by color, if you want to get the yellow color in first return 1 and red return 2 to have in position 2 etc:
const getRanking = (ele) => {
if (ele.color == "red") return 2;
if (ele.color == "yellow") return 1;
};
arr.sort((a,b) => getRanking(a) - getRanking(b))

How to reformat a JSON array into another format "grouping" based on different keys

Question: How can I reformat this JSON array by "grouping" via different keys, using ReactJS?
I have a JSON array as :
[
{Product: "Shoes", Sold: 5, Bought : 0, Reversed : 2} ,
{Product: "Table", Sold: 2, Bought : 0, Reserved : 4}
]
The reason for this is the data type I'm working with, and on realizing I need to visualize this data in a different way (due to one of the graph packages I am using) I need to structure this data as:
[
{
Status: "Sold",
Shoes : 5,
Table : 2
} ,
{
Status: "Bought",
Shoes : 0,
Table : 0
} ,
{
Status: "Reserved",
Shoes : 2,
Table : 4
}
]
So I'm grouping the data into the keys other than Product, and then the keys after this are Product with the Value being the Product and it's "status".
Frankly, I am at a complete loss as to what to do, as I'm thinking the code required to generate this would be quite convoluted, so I'm very open to know if this just is too much work.
const data = [
{
Product: "Shoes",
Sold: 5,
Bought : 0,
Reserved : 2
} , {
Product: "Table",
Sold: 2,
Bought : 0,
Reserved : 4
}
];
let resultData = [];
Object.keys(data[0]).forEach((key, idx) => {
if (idx !== 0) {
let resultUnit = {
Status: key,
};
data.forEach(item => {
return resultUnit = {
...resultUnit,
[item.Product]: item[key],
}
})
resultData.push(resultUnit);
}
})
console.log(resultData);
// 0: {Status: "Sold", Shoes: 5, Table: 2}
// 1: {Status: "Bought", Shoes: 0, Table: 0}
// 2: {Status: "Reserved", Shoes: 2, Table: 4}
You can do this using the Array.reduce function. (Actually, two reduce functions).
Here's an extensible solution that allows for other statuses.
Note that I changed everything to lowercase, as is standard convention.
const items = [
{product: "Shoes", sold: 5, bought : 0, reserved : 2} ,
{product: "Table", sold: 2, bought : 0, reserved : 4}
]
//We declare the status types here.
const keys = ["sold", "bought", "reserved"];
// Just create the initial 'statuses' array.
function initAcc(keys) {
return keys.map((key) => {
return {
status: key
}
});
}
//Here we are iterating over each item, getting it to return a single accumulator array each time.
const newItems = items.reduce((acc, cur) => {
return addItemToAccumulator(acc, cur);
}, initAcc(keys));
console.log(newItems);
// This function maps of the accumulator array (ie. over each status).
function addItemToAccumulator(acc, item) {
return acc.reduce((acc, statusLine) => {
//Find the count from the existing status if it exists,
//Add the current items count for that status to it.
const itemCount = item[statusLine.status] + (statusLine[item.product] || 0);
//Return a modified status, with the new count for that product
return [
...acc,
{
...statusLine,
[item.product]: itemCount
}
];
}, []);
}
Lets just do a simple loop function and create a couple objects to clearly solve the problem here:
const data = [YOUR_INITIAL_ARRAY];
let Sold, Bought, Reserved = {};
data.forEach(({Product, Sold, Bought, Reserved})=> {
Sold[Product] = Sold;
Bought[Product] = Bought;
Reservered[Product] = Reserved;
});
let newArray = [Sold, Bought, Reserved];
I think you can see where this is going ^ I see a few others have given complete answers, but try and go for the clear understandable route so it makes sense.
All you have to do after this is set the status which i'd do off an enum and you are good

To group of array of objects by its id value

I have a group of array of objects in which that object property has value with ID number. I am successfully group it with that ID, however I am doing it by hardcode, not dynamically.
var objBuyUser = response.newIdUserPul[i].arrayUserHistoryBuy;
for (var y = 0; y < objBuyUser.length; y++) {
if(objBuyUser[y].product_id == 1) {
var doesIdExist = vm.pulBms.filter(function(v) {
return v.userid === response.newIdUserPul[i].id;
});
if(doesIdExist.length > 0) {
//do nothhing
} else {
vm.pulBms.push({
userid:response.newIdUserPul[i].id,
buyAct: objBuyUser
});
}
}
objBuyUser[y].product_id == 1 is what will different them each other. As long as this time we only have three ID number 1, 2, 3, I just copied the same code by changing the id manually. So, anybody can help to make it dynamically?
(**)SO: actually we have the list of product: 1, 2, 3
In the backend, I have process a unique user with its history buy, assign by response.newIdUserPul[i]. And the arrayUserHistoryBuy is the array of object detailing their product history buying from the range of the date, which in the object can consiste the date, quantity, and the product_id which need to be group here (reffer to -> **). In this case, knowing that each user can buy different product in the range of date, we still group it by product since the product is exist in the history of buying.
So the output could be similar like this:
ProductID1 :
{
User: 123
ProductBuyHistory :
{
Date: 3-10-10
ProductID : 2,
Quantity: 10
},
{
Date: 4-10-10
ProductID : 1,
Quantity: 10
},
},
{
User: 124
ProductBuyHistory :
{
Date: 3-10-10
ProductID : 3,
Quantity: 10
},
{
Date: 4-10-10
ProductID : 1,
Quantity: 10
},
},
SO on for productId 2 and 3

How to weight items in a fuzzy search

Using Fuse.js, I need to weight individual item for a better ranking in search results. For instance, how do I make sure "Paris France" has the biggest score for a "Paris" query with the data below?
places = [{
name: 'Paris, France'
weigth: 10
},{
name: 'Paris, Ontario'
weigth: 2
},
{
name: 'Paris, Texas'
weigth: 1
}]
As far as I am aware, there are no methods built into Fuse.js to do this. The weight property is meant to be applied to properties which are being searched (in the options object), rather than to the object that is being searched (as seen in the example here.
What I might suggest is writing a function to sort this yourself. So once you get your results array back, after the search, perform an Array.sort() on it yourself (documentation here).
For example...
//Your places object
var places = [
{
name: 'Paris, Texas',
weight: 2
},
{
name: 'Paris, France',
weight: 10
},
{
name: 'Paris, Texas',
weight: 1
}
];
//Your search options
var options = {
keys: [
"name"
]
};
var fuse = new Fuse(places, options); // "list" is the item array
var result = fuse.search("Paris");
//Once you have got this result, perform your own sort on it:
result.sort(function(a, b) {
return b.weight - a.weight;
});
console.log('Your sorted results:');
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fuse.js/3.1.0/fuse.min.js"></script>

Categories