更新嵌套对象数组
2019-01-21
1971
使用对象数组时,我需要更新任何具有
类型
的
选择(多个答案)
对象的计数。
每个具有
类型
的
选择(多个答案)
对象都包含一个
数据
对象数组,其中以逗号分隔
值
,例如“价格过高、独特、高品质”。这些值应分离到它们自己的对象中,并包含在该特定
data
对象数组的新
count
和
total
(所有
count
值的总和)中。
const arr = [
{
data: [
{count: 7, total: 7, value: "N/A"},
],
name: "item 1",
type: "Yes/No",
}, {
data: [
{count: 5, total: 7, value: "N/A"},
{count: 2, total: 7, value: "Yellow"},
],
name: "item 2",
type: "Select (Single Answer)",
}, {
data: [
{count: 5, total: 7, value: "N/A"},
{count: 1, total: 7, value: "Overpriced,Unique,High quality"},
{count: 1, total: 7, value: "Reliable,High quality"},
],
name: "item 3",
type: "Select (Multiple Answer)",
},
];
预期结果
const result = [
{
data: [
{count: 7, total: 7, value: "N/A"},
],
name: "item 1",
type: "Yes/No",
}, {
data: [
{count: 5, total: 7, value: "N/A"},
{count: 2, total: 7, value: "Yellow"},
],
name: "item 2",
type: "Select (Single Answer)",
}, {
data: [
{count: 5, total: 10, value: "N/A"},
{count: 2, total: 10, value: "High quality"},
{count: 1, total: 10, value: "Overpriced"},
{count: 1, total: 10, value: "Unique"},
{count: 1, total: 10, value: "Reliable"},
],
name: "item 3",
type: "Select (Multiple Answer)",
},
];
我已经开始使用
reduce
函数,但它产生的对象远非期望的结果:
当前代码
arr.reduce((a, c) => {
a[c.data.value] = a[c.data.value] || { total: 0 };
a[c.data.value].total += 1;
return a;
}, {})
不良结果
{ undefined: { total: 4 } }
3个回答
您可以使用闭包收集组并获取
total
。
它具有
total
的闭包并返回一个数组
data: (total => Array.from(
))(0)
通过采用
Map
将数据收集为
initialValue
o.data.reduce(
new Map
),
以及一个使用
count
、
total
和
value
映射新对象的函数。
([value, count]) => ({ count, total, value })
在
reduce
的回调中,
count
和
value
被解构,并且值被拆分,用于获取所有计数到 map 中收集的所有拆分值。同时,
total
会随着实际计数而增加。最后返回 map
m
。
(m, { count, value }) => (value.split(',').forEach(
v => (m.set(v, (m.get(v) || 0) + count), total+= count)
), m),
var data = [{ data: [{ count: 7, total: 7, value: "N/A" }], name: "item 1", type: "Yes/No" }, { data: [{ count: 5, total: 7, value: "N/A" }, { count: 2, total: 7, value: "Yellow" }], name: "item 2", type: "Select (Single Answer)" }, { data: [{ count: 5, total: 7, value: "N/A" }, { count: 1, total: 7, value: "Overpriced,Unique,High quality" }, { count: 1, total: 7, value: "Reliable,High quality" }], name: "item 3", type: "Select (Multiple Answer)" }],
result = data.map(o => Object.assign({}, o, {
data: (total => Array.from(
o.data.reduce(
(m, { count, value }) => (value.split(',').forEach(
v => (m.set(v, (m.get(v) || 0) + count), total+= count)
), m),
new Map
),
([value, count]) => ({ count, total, value })
))(0)
}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
2019-01-21
这里有一种方法可以做到这一点,并附上一些注释以使其更清楚:
let arr = [{data:[{count:7,total:7,value:"N/A"}],name:"item 1",type:"Yes/No"},{data:[{count:5,total:7,value:"N/A"},{count:2,total:7,value:"Yellow"}],name:"item 2",type:"Select (Single Answer)"},{data:[{count:5,total:7,value:"N/A"},{count:1,total:7,value:"Overpriced,Unique,High quality"},{count:1,total:7,value:"Reliable,High quality"}],name:"item 3",type:"Select (Multiple Answer)"}];
arr.forEach(x => {
//get all splitted values
const allValues = x.data.filter(y => y.value.split(',').length > 1).reduce((a, e) => a.concat(e.value.split(',')), []);
//remove non-splitten values from data array
x.data = x.data.filter(y => y.value.split(',').length <= 1);
//create new values from old
const newData = allValues.reduce((a, y) => {
const data = a.find(z => z.value === y);
if (data) {
data.count++;
return a;
};
return a.concat({ count: 1, value: y });
}, x.data)
//create new total
const sumCounters = newData.reduce((a, e) => a + e.count, 0);
newData.forEach(e => e.total = sumCounters);
x.data = newData;
return x;
})
console.log(arr);
guijob
2019-01-21
自从我开始研究这个问题以来,已经提供了几个很好的答案,但我不想浪费我投入的时间,所以这是我的解决方案。
// OP's original array
const arr = [
{
data: [
{count: 7, total: 7, value: "N/A"},
],
name: "item 1",
type: "Yes/No",
}, {
data: [
{count: 5, total: 7, value: "N/A"},
{count: 2, total: 7, value: "Yellow"},
],
name: "item 2",
type: "Select (Single Answer)",
}, {
data: [
{count: 5, total: 7, value: "N/A"},
{count: 1, total: 7, value: "Overpriced,Unique,High quality"},
{count: 1, total: 7, value: "Reliable,High quality"},
],
name: "item 3",
type: "Select (Multiple Answer)",
},
];
arr.forEach(function(select){
// Only modify the multiple answer selects
if(select.type == 'Select (Multiple Answer)'){
var newTotal = 0; // calculate a new total as each item is added to the new array
// use reduce to create a new data array for the multiple answer select
var newDataArray = select.data.reduce(function(acc,d){
valueArr = d['value'].split(','); // get a list of separate value strings
valueArr.forEach(function(valStr){
var unique = true;
// if the new array is empty then go ahead and add the first item
if(acc.length === 0){
acc.push({'count':d.count,'total':d.total,'value':valStr});
newTotal += d.count;
} else {
// check to see if there is already an object with the same value string
// if there is then just update the count and set the unique flag so a new element doesn't get added later
acc.forEach(function(obj){
if(obj['value'] == valStr){
obj['count'] += d.count;
unique = false;
newTotal += d.count;
}
})
if(unique){
acc.push({'count':d.count,'total':d.total,'value':valStr});
newTotal += d.count;
}
}
})
return acc;
}, []);
// Update totals
newDataArray.forEach(function(obj){
obj.total = newTotal;
})
select.data = newDataArray;
}
})
console.log(arr);
T. Stoddard
2019-01-22