Как получить идентификатор пользователя после фильтра и карты - PullRequest
7 голосов
/ 22 июня 2019

Привет! Я пытаюсь создать объект с именем и идентификатором пользователя для каждой службы. Я хочу, чтобы объект выглядел следующим образом:

const object = {
    name: Netflix, user: (user id who pays max price for this provider)
    name: Comcast, user: (same)
    name: Verizon, user: (same)
}

Я пытался изменить свойство объекта на карте, ноэто не работает, также у меня уже есть половина объекта, я имею в виду имена провайдеров, теперь мне нужен другой ключ, пара значений

const services = [
     { userid: 1, providerId: 1, ammount: 250000 },
     { userid: 4, providerId: 3, ammount: 280900 },
     { userid: 6, providerId: 3, ammount: 31000 },
     { userid: 2, providerId: 2, ammount: 58600 },
     { userid: 3, providerId: 1, ammount: 13000 },
     { userid: 5, providerId: 2, ammount: 5000 },
     { userid: 3, providerId: 3, ammount: 59900 },
     { userid: 6, providerId: 3, ammount: 9500 }
]

const providers = [
    { id: 1, name: Netflix },
    { id: 2, name: Comcast },
    { id: 3, name: Verizon }
]

Это моя функция

function getUserId(providerId) {
    return services.filter(function(obj) {
        if (obj.providerId == providerId)
            return obj.providerId;
    }).map(function(obj) { return obj.ammount });
}

function getMaxUserId(providerId) {
    return Math.max(...getUserId(providerId));
}

providers.forEach(prov => {
    object[prov.name] = getUserId(prov.id);
})

как вы можете видеть, сначала я фильтрую весь массив в поисках поставщиков с определенным providerId, затем создаю новый массив с функцией map, заполненной всеми «ammounts» для этого конкретного поставщика, и, наконец, я ищу максимальное количество этого массива,все это прекрасно работает, возвращает правильную максимальную сумму для каждого провайдера, НО я также хочу получить идентификатор пользователя, который платит больше всего за каждого провайдера

на самом деле я получаю свой объект следующим образом:

[
   {name: Netflix, user: 250000},
   {name: Comcast, user: 58600},
   {name: Verizon, user: 280900}
]

и мне нужно это:

[
   {name: Netflix, user: 1},
   {name: Comcast, user: 2},
   {name: Verizon, user: 4}
]

Ответы [ 4 ]

3 голосов
/ 22 июня 2019

Вы также можете sort свои услуги на amount. Затем вы можете сгруппировать их по providerId и, наконец, отобразить поставщиков, чтобы получить желаемый результат:

const services = [ { id: 1, providerId: 1, ammount: 250000 }, { id: 4, providerId: 3, ammount: 280900 }, { id: 6, providerId: 3, ammount: 31000 }, { id: 2, providerId: 2, ammount: 58600 }, { id: 3, providerId: 1, ammount: 13000 }, { id: 5, providerId: 2, ammount: 5000 }, { id: 3, providerId: 3, ammount: 59900 }, { id: 6, providerId: 3, ammount: 9500 } ]
const providers = [ { id: 1, name: 'Netflix' }, { id: 2, name: 'Comcast' }, { id: 3, name: 'Verizon' } ] 

let grouped = services
  .sort((a,b) => b.ammount - a.ammount)  // 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)

Вы также можете пропустить sort выше и проверить ammount и на основании этого либо push, либо unshift:

const services = [ { id: 1, providerId: 1, ammount: 250000 }, { id: 4, providerId: 3, ammount: 280900 }, { id: 6, providerId: 3, ammount: 31000 }, { id: 2, providerId: 2, ammount: 58600 }, { id: 3, providerId: 1, ammount: 13000 }, { id: 5, providerId: 2, ammount: 5000 }, { id: 3, providerId: 3, ammount: 59900 }, { id: 6, providerId: 3, ammount: 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].ammount > cur.ammount) 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)

Таким образом, у вас есть только один Array.reduce и один Array.map, который будет more performant, чем ваша оригинальная версия с forEach, filter и map.

1 голос
/ 22 июня 2019

И, в качестве третьего возможного решения вашей проблемы (следуя моему комментарию), вы можете использовать что-то вроде этого (вы можете изменить объект так, как считаете нужным, но я бы предложил избавиться от * 1001).* и user в целом):

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.ammount; } );
    let idx = amm.indexOf(Math.max(...amm));
    return output[idx].userid;
}

providers.forEach(prov => {
    object[prov.name] = getMaxUserId(getUserId(prov.id));
})

console.log(object)

Вывод в вашем случае с использованием этого решения будет выглядеть следующим образом:

Object { Netflix: 1, Comcast: 2, Verizon: 4 }

Ofc, с небольшой настройкой вы сможетечтобы вернуть Array с объектами, как первоначально предполагалось (не забудьте вместо этого присвоить object []):

providers.forEach(prov => {
  object.push( {name:prov.name,user:getMaxUserId(getUserId(prov.id))} )
})

В последнем случае вывод будет выглядеть следующим образом:

Array [Object { name: "Netflix", user: 1 }, Object { name: "Comcast", user: 2 }, Object { name: "Verizon", user: 4 }]
1 голос
/ 22 июня 2019

В идеале у нас был бы argmax в JS.Но пока нормальная итерация выглядит лучше.Обратите внимание на редко встречающееся ==, потому что JS превращает ключи словаря в строки:

var maxes = {};
services.forEach(item => {
    if(!maxes[item.providerId] || maxes[item.providerId] < item.ammount[0]) {
        maxes[item.providerId] = [item.ammount, 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] };
}));
0 голосов
/ 22 июня 2019

Попробуйте следующий код.

function getUser(providerId) {
    let arr = services.filter(v => { // filters for this provider
        return v.providerId == providerId;
    });

    return arr.sort((a, b) => { // sorts from highest to lowest amount
        if (a.ammount > b.ammount) {
            return -1;
        }
        if (a.ammount < b.ammount) {
            return 1;
        }
        return 0;
    })[0]; // returns the first obj in the sorted array
}

var result = [];
providers.forEach(prov => {
    result.push({
        name: prov.name,
        userDetails: getUser(prov.id)
    });
});
console.log(result);

JSFiddle

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...