我正在尝试从另一个数组和对象构造一个对象数组。
let assets = [
{id: '1', count: 1, skills: ["teach", "play"]},
{id: '2', count: 1, skills: ["write", "surf"]},
{id: '3', count: 2, skills: ["run"]},
{id: '4', count: 3, skills: ["teach", "run", "hike"]}
]
然后,我将运用上面提供的所有独特技能。
let uniqueSkills = ["teach", "play", "write", "surf", "run", "hike"]
uniqueSkills数组中的每个元素都必须是对象中的键。而且,如果该键存在于资产数组中,那么我想存储该特定对象的id
和count
。
我希望我的最终对象是这样的东西,我将不得不使用它来绘制图形。
{
teach: [{id: 1, count: 1},{id: 4, count: 3}],
play: [{id: 1, count: 1}],
write: [{id: 2, count: 1}],
surf: [{id: 2, count: 1}],
run: [{id: 3, count: 2}, {id: 4, count: 3}],
hike: [{id: 4, count: 3}]
}
答案 0 :(得分:3)
您可以reduce
阵列。 Destructure个参数,分别获取属性skills
和rest
。然后遍历skills
并在累加器中添加/更新密钥
const assets=[{id:'1',count:1,skills:["teach","play"]},{id:'2',count:1,skills:["write","surf"]},{id:'3',count:2,skills:["run"]},{id:'4',count:3,skills:["teach","run","hike"]}]
const output = assets.reduce((acc, { skills, ...rest }) => {
skills.forEach(s => {
acc[s] = acc[s] || [];
acc[s].push(rest)
})
return acc;
}, {})
console.log(output)
(检查浏览器控制台的实际输出。代码段显示不正确)
答案 1 :(得分:1)
let finalObj = {};
uniqueSkills.map( (skill) => {
finalObj[skill] = assets.filter( asset => asset.skills.includes(skill) )
.map( asset => ({id: asset.id, count: asset.count}) );
})
这有点复杂,所以让我为您分解:
使用Array.map()
遍历所有独特技能。
我们为每个技能在最终对象中创建一个属性,并带有技能名称。
过滤资产数组以删除其skills
属性中不包含该技能的所有对象。
在从filter返回的数组上,返回仅包含id
和count
属性的数组,并将该数组放入步骤2中创建的属性中。
有关数组函数的更多信息:Array.map(),Array.filter()。
希望这会有所帮助:)
答案 2 :(得分:1)
这是不使用reduce
的解决方案,而是依靠函数生成器并使用.filter
来获取所需的过滤值。
下面的代码将迭代所有独特的技能,并针对每个技能构建一个对象。
这并不意味着要更有效率,它只是完成任务的另一种方式,它应该具有弹性并且易于维护。而且,也有可能根本不依赖任何数组原型。
下面的方法允许在需要时进行进一步的对象转换。
let assets = [
{id: '1', count: 1, skills: ["teach", "play"]},
{id: '2', count: 1, skills: ["write", "surf"]},
{id: '3', count: 2, skills: ["run"]},
{id: '4', count: 3, skills: ["teach", "run", "hike"]}
];
let uniqueSkills = ["teach", "play", "write", "surf", "run", "hike"];
// Aggregates the source results by looking for uniqueSkills in its skills property.
function* aggregateByUniqueSkills(source, uniqueSkills) {
// loop each uniques skill.
for (var skill of [...new Set(uniqueSkills)]) { // <-- new Set ensures there are no duplicates.
const skillSet = {[skill]: []}; // <-- define a new object with a key and a default empty array value.
for ({id, count} of source.filter(i => i.skills && i.skills.indexOf(skill) > -1)) { // acquire all the elements in the source whose skills contains the current skill.
skillSet[skill].push({id, count}); // push the value.
}
yield skillSet; // yield the current result.
}
}
console.log(Object.assign({}, ...aggregateByUniqueSkills(assets, uniqueSkills)));
答案 3 :(得分:0)
嗯,没有捷径可以完成。只是一个简单的算法。 这是一个可行的解决方案。
let assets = [
{ id: '1', count: 1, skills: ["teach", "play"] },
{ id: '2', count: 1, skills: ["write", "surf"] },
{ id: '3', count: 2, skills: ["run"] },
{ id: '4', count: 3, skills: ["teach", "run", "hike"] }
];
// Filter unique keys into an array
let skillKeys = [];
assets.forEach(element => {
skillKeys = [...new Set(skillKeys.concat(element['skills']))];
});
// Final refined result
let refined = {};
let temp = [];
skillKeys.forEach(sKey => {
temp = [];
assets.forEach(a => {
if (a['skills'].includes(sKey)) {
temp.push({ id: a['id'], count: a['count'] });
}
})
refined[sKey] = temp;
});
console.log(refined);