从单个数组对象创建嵌套对象数组的通用函数

generic function to create an array of nested objects from a single object of arrays

这是一个非常具体的问题,但我有一个带有数组的对象:

let rawData = {
    one: ["a", "a", "a", "b", "b", "b", "c", "c", "c"],
    two: [1,2,3,1,2,3,1,2,3],
    three: [1,4,9,3,9,7,6,5,5]
  }

并且我想编写一个通用函数,它将根据第一个数组创建一组嵌套对象(这里是 a,但我想让这个函数不依赖于特定的键。

在我的第一次尝试中,我编写了一个将其解析为对象数组的函数:

dataframe_for_plot = (data) => {
  var length
  var names = []
  for (var name in data) {
        if (data.hasOwnProperty(name))
            names.push(name);
        length = rawData[name].length;
  }

    var results = [];
    var item;
    for (var row = 0; row < length; row++) {
        item = {};
        for (var col = 0; col < names.length; col++) {
            item[names[col]] = data[names[col]][row];
        }
        results.push(item);
    }
    return results;
}

哪个产量

dataframe_for_plot(rawData)
[
  {one: "a", two: 1, three: 1},
  {one: "a", two: 2, three: 4},
  {one: "a", two: 3, three: 9},
  {one: "b", two: 1, three: 3},
  {one: "b", two: 2, three: 9},
  {one: "b", two: 3, three: 7},
  {one: "c", two: 1, three: 6},
  {one: "c", two: 2, three: 5},
  {one: "c", two: 3, three: 5},
]

但我想在此函数的基础上构建以获得我想要的输出,其中第一个键用于根据该键的唯一编号(在本例中为 3)和新的 value 创建对象创建键以包含其他键的嵌套数组(在本例中为 twothree,按 one 组合在一起)

let desired_output = [
  {
    one:"a",
    values: [
      {two:1, three:1},
      {two:2, three:4},
      {two:3, three:9}
    ],
  },
    {
    one:"b",
    values: [
      {two:1, three:3},
      {two:2, three:9},
      {two:3, three:7}
    ],
  },
    {
    one:"c",
    values: [
      {two:1, three:6},
      {two:2, three:5},
      {two:3, three:5}
    ],
  }
]

我认为我的函数是一个好的开始,但我需要一些帮助来处理嵌套的第 2 部分!谢谢!

将对象转换为条目数组,并获得第一项的keyvals。将 vals 缩减为地图。对于第一个数组中的每个唯一值,如果值(在您的情况下为 one),Map 将具有一个对象。然后迭代其他值的数组,从每个 [key, arr] 对中获取相应的值,并使用 Object.fromEntries().

将它们转换为对象

使用 Array.from().

将映射值迭代器转换回数组

const fn = obj => {
  const [[key, vals], ...values] = Object.entries(obj)
  
  return Array.from(vals.reduce((acc, v, i) => {
    if(!acc.has(v)) acc.set(v, { [key]: v, values: [] })
    
    acc.get(v).values.push(Object.fromEntries(
      values.map(([k, arr]) => [k, arr[i]])
    ))
    
    return acc
  }, new Map()).values())
}

const rawData = {
  one: ["a", "a", "a", "b", "b", "b", "c", "c", "c"],
  two: [1,2,3,1,2,3,1,2,3],
  three: [1,4,9,3,9,7,6,5,5]
}

const result = fn(rawData)

console.log(result)

如果您想控制属性的顺序,您可以传递一个 order 数组,然后按照您指定的顺序手动创建条目:

const fn = (order, obj) => {
  const [[key, vals], ...values] = order.map(key => [key, obj[key]])
  
  return Array.from(vals.reduce((acc, v, i) => {
    if(!acc.has(v)) acc.set(v, { [key]: v, values: [] })
    
    acc.get(v).values.push(Object.fromEntries(
      values.map(([k, arr]) => [k, arr[i]])
    ))
    
    return acc
  }, new Map()).values())
}

const rawData = {
  one: ["a", "a", "a", "b", "b", "b", "c", "c", "c"],
  two: [1,2,3,1,2,3,1,2,3],
  three: [1,4,9,3,9,7,6,5,5]
}

const result = fn(['one', 'three', 'two'], rawData)

console.log(result)