#javascript #lodash
#javascript #Lodash
Вопрос:
Я пытаюсь преобразовать некоторые данные с помощью Lodash groupBy и map. Вот пример данных:
var data = [
{name: 'x', qty: 0, rate: 10},
{name: 'x', qty: 10, rate: 2},
{name: 'y', qty: 5, rate: 20},
{name: 'y', qty: 55, rate: 11}]
Мне нужны эти данные в формате:
var data = [
{name: 'x', pricing: [{qty: 0, rate: 10}, {qty: 10, rate: 2}]},
{name: 'y', pricing: [{qty: 5, rate: 20}, {qty: 55, rate: 11}]}]
Ниже приведена моя попытка:
var m = _.chain(data)
.groupBy(data, 'name')
.map( function(i) {
return {
name: _.first(i).name,
pricing: _.map(i, function(r) {
return _.pick(r, ['qty', 'rate'])
})
}
})
Это приводит к
[{
"name": "x",
"pricing": [
{"qty": 0, "rate": 10},
{"qty": 10, "rate": 2},
{"qty": 5,"rate": 20},
{"qty": 55,"rate": 11}]
}]
Я не смог понять, что я делаю не так. Может быть, это даже недопустимо, и есть способ получше?
Ответ №1:
Вам нужно сопоставить новый объект и получить выбранные значения.
var data = [{ name: 'x', qty: 0, rate: 10 }, { name: 'x', qty: 10, rate: 2 }, { name: 'y', qty: 5, rate: 20 }, { name: 'y', qty: 55, rate: 11 }],
result = _(data)
.groupBy('name')
.map((pricing, name) => ({
name,
pricing: _.map(pricing, _.partialRight(_.pick, ['qty', 'rate']))
}))
.value();
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Ответ №2:
Вам не нужно использовать Lodash для этого — стандартные методы массива Javascript работают просто отлично. Сведите к объекту, проиндексированному name
, затем получите значения этого объекта:
var data = [
{name: 'x', qty: 0, rate: 10},
{name: 'x', qty: 10, rate: 2},
{name: 'y', qty: 5, rate: 20},
{name: 'y', qty: 55, rate: 11}]
const obj = data.reduce((a, { name, ...rest }) => {
if (!a[name]) a[name] = { name, pricing: [] };
a[name].pricing.push(rest);
return a;
}, {});
const output = Object.values(obj);
console.log(output);
Ответ №3:
Вы можете сделать это с помощью reduce()
var data = [
{name: 'x', qty: 0, rate: 10},
{name: 'x', qty: 10, rate: 2},
{name: 'y', qty: 5, rate: 20},
{name: 'y', qty: 55, rate: 11}]
let res = data.reduce((ac,a) => {
let i = ac.findIndex(x => x.name === a.name);
if(i === -1) i = ac.push({name:a.name,pricing:[]}) - 1
ac[i].pricing.push({qty:a.qty,rate:a.rate});
return ac;
},[])
console.log(res);
Ответ №4:
Ваш код на самом деле в порядке, за исключением небольшой ошибки. Вы начинаете цепочку с data
, а затем пытаетесь сгруппировать с помощью data
. Поскольку ни один из элементов не возвращает true
для этого предиката, все они объединены в одну группу, и это является причиной вашего единого объекта.
Вам нужно изменить .groupBy(data, 'name')
на .groupBy('name')
.
Пример:
var data = [{ name: 'x', qty: 0, rate: 10 }, { name: 'x', qty: 10, rate: 2 }, { name: 'y', qty: 5, rate: 20 }, { name: 'y', qty: 55, rate: 11 }];
var m = _.chain(data)
.groupBy('name') // group by name, and not by data, 'name'
.map(function(i) {
return {
name: _.first(i).name,
pricing: _.map(i, function(r) {
return _.pick(r, ['qty', 'rate'])
})
}
})
console.log(m);
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>