问题描述
我有数组:
array = [
{
"id": 1,"date": {
"id": 1,"name": "202001"
},"item": {
"id": 1,"name": "I1"
},"price": 100
},{
"id": 2,"date": {
"id": 2,"name": "202002"
},"price": 200
},{
"id": 3,"item": {
"id": 2,"name": "I2"
},"price": 300
},]
而且我希望能够显示表中所示的数据:
项目 | 202001 | 202002 |
---|---|---|
I1 | 100 | 200 |
I2 | - | 300 |
这个想法是将同一项目的每个日期的值分组。
我该怎么做,建议?
解决方法
您可以将整个结构简化为按项目名称索引的字典,其值为按日期索引的字典:
items_dicc = array.reduce((acc,e) => {
if (!acc[e["item"]["name"]]) {
acc[e["item"]["name"]] = {
[e["date"]["name"]]: e["price"]
}
} else {
acc[e["item"]["name"]][e["date"]["name"]] = e["price"]
}
return acc
},{})
/* items_dicc holds:
{ I1: { '202001': 100,'202002': 200 },I2: { '202002': 300 } }
*/
随后,您可以利用 items_dicc
结构来构建您要查找的表:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Document</title>
</head>
<body>
<table>
<thead>
<tr class="thead">
<th>ITEM</th>
</tr>
</thead>
<tbody class="tbody">
<tr>
<td></td>
</tr>
</tbody>
</table>
</body>
<script>
array = [
{
"id": 1,"date": {
"id": 1,"name": "202001"
},"item": {
"id": 1,"name": "I1"
},"price": 100
},{
"id": 2,"date": {
"id": 2,"name": "202002"
},"price": 200
},{
"id": 3,"item": {
"id": 2,"name": "I2"
},"price": 300
}
]
items_dicc = array.reduce((acc,e) => {
if (!acc[e["item"]["name"]]) {
acc[e["item"]["name"]] = {
[e["date"]["name"]]: e["price"]
}
} else {
acc[e["item"]["name"]][e["date"]["name"]] = e["price"]
}
return acc
},{})
// Compute dates that will be used as headers. Duplicates are removed after creating a set and turning it into a list again
dates = [...new Set(Object.keys(items_dicc).map(i => Object.keys(items_dicc[i])).flat())]
const thead = document.getElementsByClassName("thead")[0]
const tbody = document.getElementsByClassName("tbody")[0]
dates.forEach(date => {
thead.appendChild(
htmlToElement(`<th>${date}</th>`)
)
});
Object.keys(items_dicc).forEach(i => {
let row = `<tr><td>${i}</td>`
dates.forEach(date => {
row = `${row}<td>${items_dicc[i][date] || ''}</td>`
});
row = `${row}</tr>`
tbody.appendChild(htmlToElement(row))
})
// From https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro/35385518#35385518
function htmlToElement(html) {
var template = document.createElement('template');
html = html.trim();
template.innerHTML = html;
return template.content.firstChild;
}
</script>
</html>
最终结果:
<table>
<thead>
<tr class="thead">
<th>ITEM</th>
<th>202001</th>
<th>202002</th>
</tr>
</thead>
<tbody class="tbody">
<tr>
<td></td>
</tr>
<tr>
<td>I1</td>
<td>100</td>
<td>200</td>
</tr>
<tr>
<td>I2</td>
<td></td>
<td>300</td>
</tr>
</tbody>
</table>
编辑:解决方案的最简单的 React
版本:
App.js
function App() {
const array = [
{
"id": 1,"price": 300
}
]
const items_dicc = array.reduce((acc,{})
// Compute dates that will be used as headers. Duplicates are removed after creating a set and turning it into a list again
const dates = [...new Set(Object.keys(items_dicc).map(i => Object.keys(items_dicc[i])).flat())]
return (
<div className="App">
<table>
<thead>
<tr>
<th>ITEM</th>
{dates.map(date => <th>{date}</th>)}
</tr>
</thead>
<tbody>
{
Object.keys(items_dicc).map((item) => {
return (
<tr>
<td>{item}</td>
{dates.map((date) => <td>{items_dicc[item][date] || ''}</td>)}
</tr>
)
})
}
</tbody>
</table>
</div>
);
}
export default App;