英文:
Javascript compare, merge, set data from arrays to prep for table
问题
以下是您提供的代码的翻译部分:
我正在为一个表格准备后端数据,并希望以一种可以映射表格行的方式设置它。表格的标题基于用于查询数据的日期范围(始终为6个月的范围),然后我将其与数据进行比较并进行合并以设置初始对象,但然后我需要与后端的另一个数组进行比较以使行完整。
这是标题和数据数组:
const headers = ["2022-7", "2022-8", "2022-9", "2022-10", "2022-11", "2022-12"]
const data = [
{
"planDetails": {
"goals": [
{
"title": "Budget",
"frequency": 4
},
{
"title": "clean",
"frequency": 6
}
]
},
"setVisits": [
{
"goals": [
{
"k": "clean",
"v": 2
},
{
"k": "Budget",
"v": 2
}
],
"date": "2022-9"
},
{
"goals": [
{
"k": "clean",
"v": 2
},
{
"k": "Budget",
"v": 2
}
],
"date": "2022-10"
},
{
"goals": [
{
"k": "Budget",
"v": 1
},
{
"k": "clean",
"v": 2
},
],
"date": "2022-8"
}
]
}
]
然后是我采取的步骤:
const output = data.shift()
console.log(output)
const newHeader = headers.map(i => new Date(i).toISOString())
/* console.log(newHeader) */
const visits = output.setVisits.map(i => { return {date: new Date(i.date).toISOString(), goals: i.goals}})
/* console.log(visits) */
const result = newHeader.map(item => {
/* console.log(item) */
const info = visits.find(detail => detail.date === item);
/* console.log(info) */
if (info) {
return {
date: item,
goals: info.goals
}
} else {
return {
date: item,
goals: 0
}
}
})
result.sort((a,b) => a.date > b.date)
let finalArr = []
const next = output.planDetails.goals.forEach(i => {
let newObj = {}
/* console.log(i) */
if ( result.find(a => a.goals.k === i.title)) {
newObj = {
goal: i.title,
frequency: i.frequency,
elem1: {
date: a[0].date,
count: a[0].goals.v
},
elem2: {
date: a[1].date,
count: a[1].goals.v
}
}
/* 我只放了前6个元素的索引,以尝试在映射其余部分之前获得概念的证明 */
} else if (!result.find(a => a.goals.k === i.title)) {
newObj = {
goal: i.title,
frequency: i.frequency,
elems: {
date: a[0].date,
count: 0
}
}
}
finalArr.push(newObj)
})
console.log(finalArr)
希望这有助于理解您的代码。如果您有其他问题或需要进一步的帮助,请告诉我。
英文:
I'm prepping backend data for a table and want to get it set in a way so I can map out the table rows. The headers for the table is based on the date range that is used to query the data (always a 6 month spread), which I then compare and do a merge with the data to set up the initial objects, but then I need to compare with another array from the backend to make the row complete.
Here is the headers and data arrays:
const headers = [ "2022-7", "2022-8", "2022-9", "2022-10", "2022-11", "2022-12" ]
const data = [
{
"planDetails": {
"goals": [
{
"title": "Budget",
"frequency": 4
},
{
"title": "clean",
"frequency": 6
}
]
},
"setVisits": [
{
"goals": [
{
"k": "clean",
"v": 2
},
{
"k": "Budget",
"v": 2
}
],
"date": "2022-9"
},
{
"goals": [
{
"k": "clean",
"v": 2
},
{
"k": "Budget",
"v": 2
}
],
"date": "2022-10"
},
{
"goals": [
{
"k": "Budget",
"v": 1
},
{
"k": "clean",
"v": 2
},
],
"date": "2022-8"
}
]
}
]
And then the steps I've taken:
const output = data.shift()
console.log(output
)
const newHeader = headers.map(i => new Date(i).toISOString())
/* console.log(newHeader) */
const visits = output.setVisits.map(i => { return {date: new Date(i.date).toISOString(), goals: i.goals}})
/* console.log(visits) */
const result = newHeader.map(item => {
/* console.log(item) */
const info = visits.find(detail => detail.date === item);
/* console.log(info) */
if (info) {
return {
date: item,
goals: info.goals
}
} else {
return {
date: item,
goals: 0
}
}
})
result.sort((a,b) => a.date > b.date)
let finalArr = []
const next = output.planDetails.goals.forEach(i => {
let newObj = {}
/* console.log(i) */
if ( result.find(a => a.goals.k === i.title)) {
newObj = {
goal: i.title,
frequency: i.frequency,
elem1: {
date: a[0].date,
count: a[0].goals.v
},
elem2: {
date: a[1].date,
count: a[1].goals.v
}
}
/* I've only put to the 2nd index of 6 to try and get the proof of concept down before mapping the rest */
} else if (!result.find(a => a.goals.k === i.title)) {
newObj = {
goal: i.title,
frequency: i.frequency,
elems: {
date: a[0].date,
count: 0
}
}
}
finalArr.push(newObj)
})
console.log(finalArr)
Its that last step that is off and javascript makes my head spin. I'm pretty certain theres a simple way to compare the 2 fields of the objects and map that out, providing a 0 if there is no matching field, but I'm getting no where.
My ideal final array would look like:
[
{goal: 'Budget', frequency: 4, elem1: {date: "2022-7", count: 1}, elem2: {date: "2022-8", count: 3}, elem3: {date: "2022-9", count: 0}, etc.}
{goal: 'clean', frequency: 2, elem1: {date: "2022-7", count: 1}, elem2: {date: "2022-8", count: 0}, elem3: {date: "2022-9", count: 2}, etc.}
]
Thanks in advance for any input, here's a link to the fiddle: https://jsfiddle.net/joznox/rwyL928a/45/
答案1
得分: 1
你可以首先使用 Array#reduce
为特定日期的每个目标创建一个频率查找表。然后,最终结果可以使用 Array#map
创建。
const headers=["2022-7","2022-8","2022-9","2022-10","2022-11","2022-12"],data=[{planDetails:{goals:[{title:"Budget",frequency:4},{title:"clean",frequency:6}]},setVisits:[{goals:[{k:"clean",v:2},{k:"Budget",v:2}],date:"2022-9"},{goals:[{k:"clean",v:2},{k:"Budget",v:2}],date:"2022-10"},{goals:[{k:"Budget",v:1},{k:"clean",v:2},],date:"2022-8"}]}];
const o = data.shift(); // or data[0] to not mutate data
const lookup = o.setVisits.reduce((acc, {date, goals}) => {
goals.forEach(({k, v}) => (acc[date] ??= {})[k] = (acc[date][k] ?? 0) + v);
return acc;
}, {});
const res = o.planDetails.goals.map(({title: goal, frequency}) =>
({goal, frequency, ...Object.fromEntries(headers
.map((date, i) => [`elem${i+1}`, {date, count: lookup[date]?.[goal] ?? 0}]))}));
console.log(res);
.as-console-wrapper{max-height:100%!important}
英文:
You could first create a lookup table for the frequency of each goal for a particular date using Array#reduce
. Then, the final result can be created with Array#map
.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const headers=["2022-7","2022-8","2022-9","2022-10","2022-11","2022-12"],data=[{planDetails:{goals:[{title:"Budget",frequency:4},{title:"clean",frequency:6}]},setVisits:[{goals:[{k:"clean",v:2},{k:"Budget",v:2}],date:"2022-9"},{goals:[{k:"clean",v:2},{k:"Budget",v:2}],date:"2022-10"},{goals:[{k:"Budget",v:1},{k:"clean",v:2},],date:"2022-8"}]}];
const o = data.shift(); // or data[0] to not mutate data
const lookup = o.setVisits.reduce((acc, {date, goals}) => {
goals.forEach(({k, v}) => (acc[date] ??= {})[k] = (acc[date][k] ?? 0) + v);
return acc;
}, {});
const res = o.planDetails.goals.map(({title: goal, frequency}) =>
({goal, frequency, ...Object.fromEntries(headers
.map((date, i) => [`elem${i+1}`, {date, count: lookup[date]?.[goal] ?? 0}]))}));
console.log(res);
<!-- language: lang-css -->
.as-console-wrapper{max-height:100%!important}
<!-- end snippet -->
答案2
得分: 0
以下是您要翻译的内容:
另一种解决方案可能是首先整理您的数据,利用对象索引来汇总数据。
然后,一旦数据被汇总,为您的输出整理数据。
请注意,我已经将代码部分去除,只提供了翻译好的内容。如果您需要任何其他帮助,请随时告诉我。
英文:
Another solution may be to shape your data first, taking advantage of object indexes to aggregate the data.
const fields = headers.reduce((a,d)=>{
a[d] = 0;
return a;
},{});
let final= {};
for(let visit of data.pop().setVisits){
let date = new Date(visit.date)
.toISOString()
.substr(0,7)
.split('-')
.map(d=>Number.parseInt(d))
.join('-')
;
for(let goal of visit.goals){
let v = goal.v;
goal = goal.k;
final[goal] ??= {
frequency:0,
fields:Object.assign({},fields)
};
final[goal].frequency+=v;
final[goal].fields[date]+=v;
}
}
console.log(final);
Then once the data is aggregated, shape it for your output.
let finalArr = Object.entries(final).map(d=>{
let row = Object.entries(d[1].fields)
.sort(d=>{ return new Date(d[0])-new Date(d[1]); })
.map (d=>{ return {date: d[0], count: d[1]}; })
.reduce((a,d,i)=>{ a[`elem${i+1}`] = d; return a;}, {})
;
row.goal = d[0];
row.frequency = d[1].frequency;
return row;
});
console.log(finalArr);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论