数组的所有元素作为对象中的键

时间:2019-08-07 13:50:26

标签: javascript

我正在尝试从另一个数组和对象构造一个对象数组。

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数组中的每个元素都必须是对象中的键。而且,如果该键存在于资产数组中,那么我想存储该特定对象的idcount

我希望我的最终对象是这样的东西,我将不得不使用它来绘制图形。

{
  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}]
}

4 个答案:

答案 0 :(得分:3)

您可以reduce阵列。 Destructure个参数,分别获取属性skillsrest。然后遍历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}) );  
})

这有点复杂,所以让我为您分解:

  1. 使用Array.map()遍历所有独特技能。

  2. 我们为每个技能在最终对象中创建一个属性,并带有技能名称。

  3. 过滤资产数组以删除其skills属性中不包含该技能的所有对象。

  4. 在从filter返回的数组上,返回仅包含idcount属性的数组,并将该数组放入步骤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);