I am trying to create an Object with the name and user id for each service, I want the object to look like this:
const object = {
name: Netflix, user: (user id who pays max price for this provider)
name: Comcast, user: (same)
name: Verizon, user: (same)
}
I have tried changing the object property in the map return but it's not working, also I already have the object half done I mean with the names of the providers now I need the other key,value pair
const services = [
{ userid: 1, providerId: 1, amount: 250000 },
{ userid: 4, providerId: 3, amount: 280900 },
{ userid: 6, providerId: 3, amount: 31000 },
{ userid: 2, providerId: 2, amount: 58600 },
{ userid: 3, providerId: 1, amount: 13000 },
{ userid: 5, providerId: 2, amount: 5000 },
{ userid: 3, providerId: 3, amount: 59900 },
{ userid: 6, providerId: 3, amount: 9500 }
]
const providers = [
{ id: 1, name: Netflix },
{ id: 2, name: Comcast },
{ id: 3, name: Verizon }
]
This is my function
function getUserId(providerId) {
return services.filter(function(obj) {
if (obj.providerId == providerId)
return obj.providerId;
}).map(function(obj) { return obj.amount });
}
function getMaxUserId(providerId) {
return Math.max(...getUserId(providerId));
}
providers.forEach(prov => {
object[prov.name] = getUserId(prov.id);
})
as you can see first I filter the entire array looking for the providers with certain providerId then I create a new array with map function filled with all the 'amounts' for that particular provider and last I search for the max amount of that array, this all works fine it return the right max amount for each provider BUT I also want to get the user id who's paying the most for each provider
actually I'm getting my object like this:
[
{name: Netflix, user: 250000},
{name: Comcast, user: 58600},
{name: Verizon, user: 280900}
]
and I need this:
[
{name: Netflix, user: 1},
{name: Comcast, user: 2},
{name: Verizon, user: 4}
]
You could also sort
your services on the amount
. Then you can group them by the providerId
and finally map over the providers to get the output you want:
const services = [ { id: 1, providerId: 1, amount: 250000 }, { id: 4, providerId: 3, amount: 280900 }, { id: 6, providerId: 3, amount: 31000 }, { id: 2, providerId: 2, amount: 58600 }, { id: 3, providerId: 1, amount: 13000 }, { id: 5, providerId: 2, amount: 5000 }, { id: 3, providerId: 3, amount: 59900 }, { id: 6, providerId: 3, amount: 9500 } ]
const providers = [ { id: 1, name: 'Netflix' }, { id: 2, name: 'Comcast' }, { id: 3, name: 'Verizon' } ]
let grouped = services
.sort((a,b) => b.amount - a.amount) // sort `desc`
.reduce((r,c) => ((r[c.providerId] = r[c.providerId] || []).push(c), r), {})
let result = providers.map(p => ({name: p.name, user: grouped[p.id][0].id}))
console.log(result)
You could also skip the sort
above and check the amount
and based on that either push
or unshift
:
const services = [ { id: 1, providerId: 1, amount: 250000 }, { id: 4, providerId: 3, amount: 280900 }, { id: 6, providerId: 3, amount: 31000 }, { id: 2, providerId: 2, amount: 58600 }, { id: 3, providerId: 1, amount: 13000 }, { id: 5, providerId: 2, amount: 5000 }, { id: 3, providerId: 3, amount: 59900 }, { id: 6, providerId: 3, amount: 9500 } ]
const providers = [ { id: 1, name: 'Netflix' }, { id: 2, name: 'Comcast' }, { id: 3, name: 'Verizon' } ]
let groupedById = services.reduce((acc, cur) => {
let k = cur.providerId
acc[k] = acc[k] || []
if(acc[k][0] && acc[k][0].amount > cur.amount) acc[k].push(cur)
else acc[k].unshift(cur)
return acc
}, {})
let result = providers.map(({name, id}) => ({name, user: groupedById[id][0].id}))
console.log(result)
This way you only have one Array.reduce
and one Array.map
which will be more performant
than your original version which has forEach
, filter
and map
.
And, as a third possible solution to your problem (following up on my comment), you can use something like this (you can modify the object however you deem more to your liking, but I would suggest getting rid of name
and user
keys altogether):
const object = {};
function getUserId(providerId) {
return services.filter(function(obj) {
if (obj.providerId == providerId)
return obj.providerId;
}).map(function(obj) { return obj });
}
function getMaxUserId(output) {
let amm = output.map( (o) => { return o.amount; } );
let idx = amm.indexOf(Math.max(...amm));
return output[idx].userid;
}
providers.forEach(prov => {
object[prov.name] = getMaxUserId(getUserId(prov.id));
})
console.log(object)
The output in your case using this solution will look like this:
Object { Netflix: 1, Comcast: 2, Verizon: 4 }
Ofc, with a small tweak you will be able to return an Array
with objects as originally intended (don't forget to assign object
to []
instead):
providers.forEach(prov => {
object.push( {name:prov.name,user:getMaxUserId(getUserId(prov.id))} )
})
In the latter case the output will look like this:
Array [Object { name: "Netflix", user: 1 }, Object { name: "Comcast", user: 2 }, Object { name: "Verizon", user: 4 }]
Ideally we'd have argmax in JS. But for now, normal iteration looks nicer. Note the rarely-seen ==
because JS turns the dictionary keys into strings:
var maxes = {};
services.forEach(item => {
if(!maxes[item.providerId] || maxes[item.providerId] < item.amount[0]) {
maxes[item.providerId] = [item.amount, item.id];
}
});
function providerById(id) {
return providers.filter(p => p.id == key)[0].name;
}
console.log(Object.keys(maxes).map(key => {
return { name: providerById(key), user: maxes[key][1] };
}));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With