从树对象构建对象数组

build array of object from tree object

我正在尝试进入 javascript 的内置 reduce 函数,并借助于在数组中构建对象。 但是你可以使用任何你想要的功能或方法。

预期输出

[
  { 'team1': [14697807552, 6858384], '2021': [14697807552, 6858384], 'pepsi': [null, null], 'cola': [14697807552, 6858384] },
  { 'team2': [10268029152, 6922128], '2021': [10268029152, 6922128], 'pepsi': [null, 4800], 'cola': [10268029152, 6917328] },
]

我尝试做的事情

我创建了一个函数,它将数组作为参数并为每个数组的元素调用 reduce。

function transform(arr, obj = {}) {
  return arr.reduce((acc, item) => {
    const newObj = {};
    newObj[item.name] = item.metrics;
    acc.push(newObj);

    if (item.children) {
      transform(item.children, newObj);
    }

    return acc;
  }, []);
}
console.log(transform(arr))
<script>
  const arr = [{
      "name": "team1",
      "metrics": [
        14697807552,
        6858384
      ],
      "children": [{
        "name": "2021",
        "metrics": [
          14697807552,
          6858384
        ],
        "children": [{
            "name": "pepsi",
            "metrics": [
              null,
              null
            ]
          },
          {
            "name": "cola",
            "metrics": [
              14697807552,
              6858384
            ]
          }
        ]
      }]
    },
    {
      "name": "team2",
      "metrics": [
        10268029152,
        6922128
      ],
      "children": [{
        "name": "2021",
        "metrics": [
          10268029152,
          6922128
        ],
        "children": [{
            "name": "pepsi",
            "metrics": [
              null,
              4800
            ]
          },
          {
            "name": "cola",
            "metrics": [
              10268029152,
              6917328
            ]
          }
        ]
      }]
    }
  ]
</script>

但它给了我不想要的输出:

[
  { team1: [ 14697807552, 6858384 ] },
  { team2: [ 10268029152, 6922128 ] }
]

如果您不明白我的问题或有疑问,请问我。感谢关注!

transform 函数不对第二个参数 obj 执行任何操作,因此当您递归调用 transform 时,newObj 不会被扩展:这使得递归调用失去了任何预期的效果。

您可以使用 Object.assign 收集 所有从递归返回的对象,然后将它们合并为一个对象,而不是传递第二个参数:

const convert = arr =>
    arr?.map(({name, metrics, children}) => 
        Object.assign({[name]: metrics}, ...convert(children))) ?? [];

const arr = [{"name": "team1","metrics": [14697807552,6858384],"children": [{"name": "2021","metrics": [14697807552,6858384],"children": [{"name": "pepsi","metrics": [null,null]},{"name": "cola","metrics": [14697807552,6858384]}]}]},{"name": "team2","metrics": [10268029152,6922128],"children": [{"name": "2021","metrics": [10268029152,6922128],"children": [{"name": "pepsi","metrics": [null,4800]},{"name": "cola","metrics": [10268029152,6917328]}]}]}];

console.log(convert(arr));

请注意,像“2021”这样的 属性 是一个 index 并且将排在其他 non-index 属性之前。即使你打印一个像 { 'a': 2, '2021': 1 } 这样的对象,你也会因为同样的原因得到相反顺序的键。

如果对象键的 order 对您很重要,那么您应该使用成对数组而不是普通对象。当你需要顺序时,数组是选择的结构,当顺序不是必需的时候应该使用普通对象。

我找到了一些不同的解决方案:) 它比@trincot 的回答长,但也有效

const arr = [{"name": "team1","metrics": [14697807552,6858384],"children": [{"name": "2021","metrics": [14697807552,6858384],"children": [{"name": "pepsi","metrics": [null,null]},{"name": "cola","metrics": [14697807552,6858384]}]}]},{"name": "team2","metrics": [10268029152,6922128],"children": [{"name": "2021","metrics": [10268029152,6922128],"children": [{"name": "pepsi","metrics": [null,4800]},{"name": "cola","metrics": [10268029152,6917328]}]}]}];

const handleArr = (list, rez) => {
  list.forEach((item) => {
    rez[item.name] = item.metrics;
    item.children && handleArr(item.children, rez);
  });
};

const handle = (list) => {
  const rezArr = [];
  for (const item of list) {
    const rezObj = { [item.name]: item.metrics };
    item.children && handleArr(item.children, rezObj);
    rezArr.push(rezObj);
  }
  return rezArr;
};

console.log(handle(arr));

这种方法 returns 不同的结果,并使用所有先前的信息来获得数据的 denormalization

const
    flat = array => array.flatMap(({ name, metrics, children }) => children
        ? flat(children).map(q => ({ [name]: metrics, ...q }))
        : { [name]: metrics }),
    data = [{ name: "team1", metrics: [14697807552, 6858384], children: [{ name: "2021", metrics: [14697807552, 6858384], children: [{ name: "pepsi", metrics: [null, null] }, { name: "cola", metrics: [14697807552, 6858384] }] }] }, { name: "team2", metrics: [10268029152, 6922128], children: [{ name: "2021", metrics: [10268029152, 6922128], children: [{ name: "pepsi", metrics: [null, 4800] }, { name: "cola", metrics: [10268029152, 6917328] }] }] }],
    result = flat(data);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }