数据的转换方法如下:
const data = [{
"name": "Concert 1",
"sponsors": [
{"name": "Woolworths","location": "Melbourne"},
{"name": "Coles","location": "Melbourne"},
{"name": "Metricon","location": "Wagga Wagga"}
]
},
{
"name": "Concert 2",
"sponsors": [
{"name": "Metricon","location": "Albert Park"},
{"name": "Woolworths","location": "Melbourne"},
{"name": "ALDI","location": "Bendigo"}
]
},
{
"name": "Concert 3",
"sponsors": [
{"name": "Holcim","location": "Bendigo"},
{"name": "Westpac","location": "Melbourne"},
{"name": "Coles","location": "Mildura"}
]
}
];
const byLocation = data.reduce((r, con) => (con.sponsors.forEach(sp => {
if (!r[sp.location]) r[sp.location] = {};
if (!r[sp.location][sp.name]) r[sp.location][sp.name] = [];
r[sp.location][sp.name].push(con.name);
}), r), {});
console.log(byLocation);
以上解释:
要转换初始的data Array 的音乐会
[
concert,
concert,
// ...
]
放入对象 - 所有属性名称(位置)都是唯一的
{
"location name 1": {},
"location name 2": {},
// ...
}
第一个想法是使用Array.prototype.reduce() MDN:
const byLocation = data.reduce((resultObject, concert) => {
// Insert concert data into resultObject here
return resultObject; // Return the Object for the next iteration
}, {}); // << {} is the resultObject
为了简短起见,进行了一些重命名,通过使用 箭头函数的隐式返回(没有包装花括号),我们可以将上面的内容转换/缩短为:
const byLocation = data.reduce((r, con) => (/*Insert con data into r*/, r), {});
所以con 是迭代Concert,r 是我们需要构建的Resulting final Object。
让我们通过forEach 填充r 对象-ing con.sponsors 数组
con.sponsors.forEach(sp => { // sp is the iterating Sponsor
// If r["location name"] does not exists, create it as empty object
if (!r[sp.location]) r[sp.location] = {};
// If r["location name"]["Sponsor name"] does not exists, create it
// as an empty array
if (!r[sp.location][sp.name]) r[sp.location][sp.name] = [];
// Finally push the Concert name into that array.
r[sp.location][sp.name].push(con.name);
})
如果概念太高级,也可以这样写:
const data = [{
"name": "Concert 1",
"sponsors": [
{"name": "Woolworths","location": "Melbourne"},
{"name": "Coles","location": "Melbourne"},
{"name": "Metricon","location": "Wagga Wagga"}
]
},
{
"name": "Concert 2",
"sponsors": [
{"name": "Metricon","location": "Albert Park"},
{"name": "Woolworths","location": "Melbourne"},
{"name": "ALDI","location": "Bendigo"}
]
},
{
"name": "Concert 3",
"sponsors": [
{"name": "Holcim","location": "Bendigo"},
{"name": "Westpac","location": "Melbourne"},
{"name": "Coles","location": "Mildura"}
]
}
];
const byLocation = {}; // The resulting object of unique Locations
data.forEach((concert) => {
const sponsors = concert.sponsors;
sponsors.forEach((sponsor) => {
if (!byLocation.hasOwnProperty(sponsor.location)) {
byLocation[sponsor.location] = {};
}
if (!byLocation[sponsor.location].hasOwnProperty(sponsor.name)) {
byLocation[sponsor.location][sponsor.name] = [];
}
byLocation[sponsor.location][sponsor.name].push(concert.name);
});
});
console.log(byLocation);
用 JavaScript 显示 <ul id="list"></ul> 内的数据:
const html = Object.entries(byLocation).reduce((h, [location, ob]) => {
h += `<li>${location}<ul>`;
Object.entries(ob).forEach(([sponsor, concerts]) => {
h += `<li>${sponsor}
<ul>
<li>${concerts.join('</li><li>')}</li>
</ul>
</li>`;
});
h += `</ul></li>`;
return h
}, '');
document.querySelector('#list').insertAdjacentHTML('beforeend', html);