使用reduce扁平化数组后更改特定对象值,如何操作?

Change specific object value after array is flattened with reduce, how to?

提问人:Petervw 提问时间:9/15/2023 更新时间:9/15/2023 访问量:32

问:

我有一个嵌套的对象数组,可以深入多个级别。出于其他目的,我不得不将对象数组展平为 1 级(非嵌套)数组。 当我只知道 ID 时,如何更新 1 个特定对象?

以下是对象数组的示例:

let items = [
  {
    id: 2,
    test: false,
    items: []
  },
  {
    id: 3,
    test: false,
    items: [
      {
        id: 4,
        test: false,
        items: [
          {
            id: 10,
            test: false,
            items: []
          },
        ]
      },
    ]
  },
  {
    id: 1,
    test: false,
    items: []
  },
];

我从这个线程中使用了这个扁平化方法: 递归深度扁平 JavaScript 对象

function flatten(xs) {
  return xs.reduce((acc, x) => {
    acc = acc.concat(x);
    if (x.items) {
      acc = acc.concat(flatten(x.items));
      x.items = [];
    }
    return acc;
  }, []);
}

假设我想将测试更新为 true,仅在 id 10 中。在原始阵列上执行此操作的最简单方法是什么?当我更新扁平化数组对象时,引用不再链接到原始数组。

JavaScript 数组 对象 引用 减少

评论

0赞 cmgchess 9/15/2023
递归搜索原始和更新?像DFS一样

答:

2赞 Alexander Nenashev 9/15/2023 #1

由于对象具有硬结构,因此可以递归迭代其项并找到目标对象:

const findObject = (items, id) => {
  for(const item of items){
    if(item.id === id){
      return item;
    }
    if(item.items.length){
      const found = findObject(item.items, id);
      if(found) return found;
    }
  }
  return null;
};

const found = findObject(items, 10)
found.test = true;

console.log(items);
<script>
let items = [
  {
    id: 2,
    test: false,
    items: []
  },
  {
    id: 3,
    test: false,
    items: [
      {
        id: 4,
        test: false,
        items: [
          {
            id: 10,
            test: false,
            items: []
          },
        ]
      },
    ]
  },
  {
    id: 1,
    test: false,
    items: []
  },
];
</script>

更高级的代码将具有一个函数来遍历树和更新项目。

例如,在这里,我们将 id 为 3 的 item 及其所有后代更新为:testtrue

const transformTree = (items, filterCb, updateCb, parents = []) => {
  for(const item of items){
    if(filterCb(item, parents)){
      if(false === updateCb(item, parents)){
        return false;
      }
    }
    if(item.items.length){
      if(false === transformTree(item.items, filterCb, updateCb, parents.concat(item))){
        return false;
      }
    }
  }
};

transformTree(items, 
  // filter id === 3 and all descendants
  (item, parents) => item.id === 3 || parents.some(parent => parent.id === 3), 
  // update test to true
  item => item.test = true
);

console.log(items);
<script>
let items = [
  {
    id: 2,
    test: false,
    items: []
  },
  {
    id: 3,
    test: false,
    items: [
      {
        id: 4,
        test: false,
        items: [
          {
            id: 10,
            test: false,
            items: []
          },
        ]
      },
    ]
  },
  {
    id: 1,
    test: false,
    items: []
  },
];
</script>