从另一个包含虚拟对象的对象数组创建一个对象数组

3

我想要从另一个对象数组创建对象数组以绘制图表。

这是我用来放置对象位置的预期对象的数组。

let uniqueSkills = ['Using', 'Analyzing', 'Summarizing', 'Inferring', 'Predicting', 'Activating']

这就是需要修改的对象。

let data = {
      data0:[
        {count: 1, length: 1, skill: "Activating"},
        {count: 4, length: 1, skill: "Using"},
        {count: 2, length: 1, skill: "Analyzing"}
      ],
      data1: [
        {count: 2, length: 1, skill: "Summarizing"}
      ],
      data2: [
        {count: 1, length: 1, skill: "Predicting"},
        {count: 4, length: 1, skill: "Analyzing"}
      ]
    }

最终的结果对象应该像这样。
data = {
      data0:[
        {count: 4, length: 1, skill: "Using"},
        {count: 2, length: 1, skill: "Analyzing"},
        {skill: "Summarizing"},
        {skill: "Inferring"},
        {skill: "Predicting"},
        {count: 4, length: 1, skill: "Activating"}

      ],
      data1: [
        {skill: "Using"},
        {skill: "Analyzing"},
        {count: 2, length: 1, skill: "Summarizing"},
        {skill: "Inferring"},
        {skill: "Predicting"},
        {skill: "Activating"}
      ],
      data2: [
        {skill: "Using"},
        {count: 4, length: 1, skill: "Analyzing"},
        {skill: "Summarizing"},
        {skill: "Inferring"},
        {count: 1, length: 1, skill: "Predicting"},
        {skill: "Activating"}
      ]
    }

我写的算法在某些情况下能够正常工作,但在其他情况下会出现问题。以下是代码片段:
Object.keys(data).forEach(key => {      
      for (let i = 0; i < uniqueSkills.length; i++) {       
        if (typeof data[key][i] == 'object') {      
          if (data[key][i].skill !== uniqueSkills[i]) {     
            let index = uniqueSkills.indexOf(data[key][i].skill)
            if (typeof data[key][index] == 'object') {
              let anotherIndex = uniqueSkills.indexOf(data[key][index].skill)
              let elementAtIndex = data[key][index]
              let elementAtAnotherIndex = data[key][anotherIndex]
              data[key][i] = elementAtIndex
              data[key][index] = elementAtAnotherIndex
            }
            else {
              data[key][index] = data[key][i]
              data[key][i] = {skill: uniqueSkills[i]}
            }
          }
        } else {        
          data[key][i] = {skill: uniqueSkills[i]}       
        }       
      }     
    })
2个回答

4
你可以使用Map首先创建一个只包含对象中skill属性的空模板,然后用实际数据填充该Map。可以使用Object.entriesObject.fromEntries将普通对象与数组进行转换。
由于Map保留插入顺序,输出顺序将得到保证。

let uniqueSkills = ['Using', 'Analyzing', 'Summarizing', 'Inferring', 'Predicting', 'Activating']
let data = {data0:[{count: 1, length: 1, skill: "Activating"},{count: 4, length: 1, skill: "Using"},{count: 2, length: 1, skill: "Analyzing"}],data1: [{count: 2, length: 1, skill: "Summarizing"}],data2: [{count: 1, length: 1, skill: "Predicting"},{count: 4, length: 1, skill: "Analyzing"}]};

let newData = Object.fromEntries(Object.entries(data).map(([k, arr]) =>
    [k, Array.from(arr.reduce(
        (map, o) => map.set(o.skill, o),
        new Map(uniqueSkills.map(skill => [skill, { skill }]))
    ).values())]
));

console.log(newData);

请注意,此解决方案的最坏时间复杂度为 O(n²)(就uniqueSkills长度而言)。 您自己的解决方案的时间复杂度为 O(n³),其中包括两个外部循环(forEachfor)以及嵌套调用indexOf,后者也表示一个循环。其他解决方案,代替indexOf 的嵌套findfindIndex,其时间复杂度也为 O(n³)。 使用Map#get 而不是这些数组方法之一,将复杂度降至 O(n²)
此解决方案不会更改原始的 data 对象。 它会生成一个新对象。 但是,新对象仍将包括在原始 data 数组中找到的原始对象。
您的解决方案存在问题,即您沿着 i index anotherIndex 的路径走,尝试移动挡住您要插入的对象的对象。 但是,这条路径甚至可以比这更长。 这种创建间隙,移动到下一个位置,创建间隙等“行走”的方法,先验上不受长度限制。

1
实际上,我写的算法时间复杂度很差。非常感谢您提供的解决方案。它易于理解和阅读。 - kaleem

2
对于数据中的每个对象,调用Array.prototype.map来查找uniqueSkills中的对象。如果找到,则返回该对象;如果未找到,则返回一个新对象。

将数组替换为原始数据。

let uniqueSkills = ['Using', 'Analyzing', 'Summarizing', 'Inferring', 'Predicting', 'Activating']
let data = {data0:[{count: 1, length: 1, skill: "Activating"},{count: 4, length: 1, skill: "Using"},{count: 2, length: 1, skill: "Analyzing"}],data1: [{count: 2, length: 1, skill: "Summarizing"}],data2: [{count: 1, length: 1, skill: "Predicting"},{count: 4, length: 1, skill: "Analyzing"}]};

Object.keys(data).forEach(key => {
  data[key] =
    uniqueSkills.map(skill => data[key].find(e => e.skill === skill) || { skill });
});

console.log(data);


完美地使用了ES6,使得它变得非常简单。非常感谢。 - kaleem
这是一个不错的解决方案,但我不会称其为完美,因为它的时间复杂度不是最优的 *O(n³)*。 - trincot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接