递归根据传递的键更新父子信息

huangapple go评论77阅读模式
英文:

Recursively update parent child info based on key passed

问题

以下是您提供的代码和说明的翻译:

我有一个看起来像这样的对象数组

const data = [
  {
    key: "id1",
    name: "Category 1",
    curr: 0,
    total: 0,
    nodes: [
      {
        key: "id2",
        name: "Applications",
        curr: 20,
        total: 30,
        nodes: [
          {
            key: "id3",
            name: "Gaming",
            curr: 5,
            total: 10,
            nodes: []
          },
          {
            key: "id4",
            name: "Operating System",
            curr: 15,
            total: 20,
            nodes: []
          }
        ]
      }
    ]
  },
  {
    key: "id5",
    name: "Category 2",
    curr: 0,
    total: 0,
    nodes: [
      {
        key: "id6",
        name: "Sub Category",
        curr: 12,
        total: 48,
        nodes: [
          {
            key: "id7",
            name: "Inside Sub",
            curr: 12,
            total: 48,
            nodes: []
          }
        ]
      }
    ]
  },
  {
    key: "id8",
    name: "Last One",
    curr: 0,
    total: 0,
    nodes: []
  }
];

每个级别的 key 属性在整个树中都是唯一的。当我将键和此数组传递给一个函数时,它应该递增匹配键级别的 curr 值,此递增应该一直延伸到级别 1。请注意,不应更新级别 0 的项目。所以基本上当我传递 incrementRecursively(data, "id4") 时,输出应该如下所示,

const output = [
  {
    key: "id1",
    name: "Category 1",
    curr: 0,
    total: 0,
    nodes: [
      {
        key: "id2",
        name: "Applications",
        curr: 21,
        total: 30,
        nodes: [
          {
            key: "id3",
            name: "Gaming",
            curr: 5,
            total: 10,
            nodes: []
          },
          {
            key: "id4",
            name: "Operating System",
            curr: 16,
            total: 20,
            nodes: []
          }
        ]
      }
    ]
  },
  {
    key: "id5",
    name: "Category 2",
    curr: 0,
    total: 0,
    nodes: [
      {
        key: "id6",
        name: "Sub Category",
        curr: 12,
        total: 48,
        nodes: [
          {
            key: "id7",
            name: "Inside Sub",
            curr: 12,
            total: 48,
            nodes: []
          }
        ]
      }
    ]
  },
  {
    key: "id8",
    name: "Last One",
    curr: 0,
    total: 0,
    nodes: []
  }
];

我尝试的代码如下,

const incrementRecursively = (nodes, key) => {
  const increment = (nodes, key) => {
    nodes.forEach((node) => {
      if (node.key === key) {
        node.curr++;
      }
      if (node.nodes.length) {
        increment(node.nodes, key);
      }
    });
  };
  increment(nodes, key);
  return nodes;
};

有人能帮助我如何更新父级而不递增根值吗?


如果您需要更多帮助或有其他问题,请随时提出。
<details>
<summary>英文:</summary>
I have an array of object that look this,

const data = [
{
key: "id1",
name: "Category 1",
curr: 0,
total: 0,
nodes: [
{
key: "id2",
name: "Applications",
curr: 20,
total: 30,
nodes: [
{
key: "id3",
name: "Gaming",
curr: 5,
total: 10,
nodes: []
},
{
key: "id4",
name: "Operating System",
curr: 15,
total: 20,
nodes: []
}
]
}
]
},
{
key: "id5",
name: "Category 2",
curr: 0,
total: 0,
nodes: [
{
key: "id6",
name: "Sub Category",
curr: 12,
total: 48,
nodes: [
{
key: "id7",
name: "Inside Sub",
curr: 12,
total: 48,
nodes: []
}
]
}
]
},
{
key: "id8",
name: "Last One",
curr: 0,
total: 0,
nodes: []
}
];

`key` property at each level is unique across the entire tree. When I pass in key and this array to a functon, it should increment the `curr` value at the matching key level and this increment should go all the way upto level 1. Note that level 0 items should not be updated. So basically when I pass `incrementRecursively(data, &quot;id4&quot;)`, the output should look like,

const output = [
{
key: "id1",
name: "Category 1",
curr: 0,
total: 0,
nodes: [
{
key: "id2",
name: "Applications",
curr: 21,
total: 30,
nodes: [
{
key: "id3",
name: "Gaming",
curr: 5,
total: 10,
nodes: []
},
{
key: "id4",
name: "Operating System",
curr: 16,
total: 20,
nodes: []
}
]
}
]
},
{
key: "id5",
name: "Category 2",
curr: 0,
total: 0,
nodes: [
{
key: "id6",
name: "Sub Category",
curr: 12,
total: 48,
nodes: [
{
key: "id7",
name: "Inside Sub",
curr: 12,
total: 48,
nodes: []
}
]
}
]
},
{
key: "id8",
name: "Last One",
curr: 0,
total: 0,
nodes: []
}
];

The code that I tried,

const incrementRecursively = (nodes, key) => {
const increment = (nodes, key) => {
nodes.forEach((node) => {
if (node.key === key) {
node.curr++;
}
if (node.nodes.length) {
increment(node, key);
}
});
};
increment(nodes, key);
return nodes;
};

Can someone help how to update the parent and not increment roots value?
</details>
# 答案1
**得分**: 2
以下是翻译好的部分:
```javascript
function inc(nodes, key, depth = 0) {
for (let n of nodes)
if (n.key === key || inc(n.nodes ?? [], key, depth + 1)) {
if (depth > 0)
n.curr++
return true
}
}
inc(data, 'id7')

这段代码的想法是,如果当前节点已经直接或间接地增加,以便父节点可以相应地进行更新,就返回true

英文:

Something like this should work:

function inc(nodes, key, depth = 0) {
for (let n of nodes)
if (n.key === key || inc(n.nodes ?? [], key, depth + 1)) {
if (depth &gt; 0)
n.curr++
return true
}
}
inc(data, &#39;id7&#39;)

The idea is to return true if the current node has been directly or indirectly incremented so that the parent can update accordingly.

答案2

得分: 2

我认为这段代码会完成任务:

(基于@gog的回答,希望这个解释清楚)

function inc(nodes, key, depth = 0) {
  for (let n of nodes) {
    const nodeOwnKeyMatches = n.key === key; 
    const nodeChildsKeyMatches = inc(n.nodes, key, depth + 1);

    if (!nodeOwnKeyMatches && !nodeChildsKeyMatches) continue;

    if (nodeOwnKeyMatches || depth > 0) n.curr++;

    return true;
  }
}

const data = [
  {
    key: "id1",
    name: "Category 1",
    curr: 0,
    total: 0,
    nodes: [
      {
        key: "id2",
        name: "Applications",
        curr: 20,
        total: 30,
        nodes: [
          {
            key: "id3",
            name: "Gaming",
            curr: 5,
            total: 10,
            nodes: [],
          },
          {
            key: "id4",
            name: "Operating System",
            curr: 15,
            total: 20,
            nodes: [],
          },
        ],
      },
    ],
  },
  {
    key: "id5",
    name: "Category 2",
    curr: 0,
    total: 0,
    nodes: [
      {
        key: "id6",
        name: "Sub Category",
        curr: 12,
        total: 48,
        nodes: [
          {
            key: "id7",
            name: "Inside Sub",
            curr: 12,
            total: 48,
            nodes: [],
          },
        ],
      },
    ],
  },
  {
    key: "id8",
    name: "Last One",
    curr: 0,
    total: 0,
    nodes: [],
  },
];

inc(data, "id4");

console.log(data);
英文:

I think this code will do the job:

(it's based on @gog answer and is self-explanatory hopefully)

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

function inc(nodes, key, depth = 0) {
for (let n of nodes) {
const nodeOwnKeyMatches = n.key === key; 
const nodeChildsKeyMatches = inc(n.nodes, key, depth + 1);
if (!nodeOwnKeyMatches &amp;&amp; !nodeChildsKeyMatches) continue;
if (nodeOwnKeyMatches || depth &gt; 0) n.curr++;
return true;
}
}
const data = [
{
key: &quot;id1&quot;,
name: &quot;Category 1&quot;,
curr: 0,
total: 0,
nodes: [
{
key: &quot;id2&quot;,
name: &quot;Applications&quot;,
curr: 20,
total: 30,
nodes: [
{
key: &quot;id3&quot;,
name: &quot;Gaming&quot;,
curr: 5,
total: 10,
nodes: [],
},
{
key: &quot;id4&quot;,
name: &quot;Operating System&quot;,
curr: 15,
total: 20,
nodes: [],
},
],
},
],
},
{
key: &quot;id5&quot;,
name: &quot;Category 2&quot;,
curr: 0,
total: 0,
nodes: [
{
key: &quot;id6&quot;,
name: &quot;Sub Category&quot;,
curr: 12,
total: 48,
nodes: [
{
key: &quot;id7&quot;,
name: &quot;Inside Sub&quot;,
curr: 12,
total: 48,
nodes: [],
},
],
},
],
},
{
key: &quot;id8&quot;,
name: &quot;Last One&quot;,
curr: 0,
total: 0,
nodes: [],
},
];
inc(data, &quot;id4&quot;);
console.log(data);

<!-- end snippet -->

答案3

得分: 1

你可以实现一个遍历器来遍历这棵树。

const main = () => {
  incrementRecursively(data, 'id4');
  console.log(data);
};

const incrementRecursively = (nodeList, key) => {
  const childPredicate = (node) => node.key === key;
  walkForest(nodeList, (node, parent, depth) => {
    const isChild = depth > 0; /* or parent != null */
    if (isChild && childMatches(node, childPredicate)) {
      node.curr++;
    }
  });
};

// 后序遍历
const walkTree = (tree, walker, parent = null, depth = 0) => {
  if (tree.nodes?.length) {
    tree.nodes.forEach(node => walkTree(node, walker, tree, depth + 1));
  }
  walker(tree, parent, depth);
};

const walkForest = (forest, walker) => {
  forest.forEach(tree => walkTree(tree, walker));
};

const childMatches = (node, predicate) =>
  predicate(node) || node.nodes.some(child => childMatches(child, predicate));

const data = [{
    key: "id1",
    name: "Category 1",
    curr: 0,
    total: 0,
    nodes: [{
      key: "id2",
      name: "Applications",
      curr: 20,
      total: 30,
      nodes: [{
        key: "id3",
        name: "Gaming",
        curr: 5,
        total: 10,
        nodes: []
      }, {
        key: "id4",
        name: "Operating System",
        curr: 15,
        total: 20,
        nodes: []
      }]
    }]
  },
  {
    key: "id5",
    name: "Category 2",
    curr: 0,
    total: 0,
    nodes: [{
      key: "id6",
      name: "Sub Category",
      curr: 12,
      total: 48,
      nodes: [{
        key: "id7",
        name: "Inside Sub",
        curr: 12,
        total: 48,
        nodes: []
      }]
    }]
  },
  {
    key: "id8",
    name: "Last One",
    curr: 0,
    total: 0,
    nodes: []
  }
];

main();
.as-console-wrapper { top: 0; max-height: 100% !important; }
英文:

You could implement a walker to step through the tree.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const main = () =&gt; {
incrementRecursively(data, &#39;id4&#39;);
console.log(data);
};
const incrementRecursively = (nodeList, key) =&gt; {
const childPredicate = (node) =&gt; node.key === key;
walkForest(nodeList, (node, parent, depth) =&gt; {
const isChild = depth &gt; 0; /* or parent != null */
if (isChild &amp;&amp; childMatches(node, childPredicate)) {
node.curr++;
}
});
};
// Post-order
const walkTree = (tree, walker, parent = null, depth = 0) =&gt; {
if (tree.nodes?.length) {
tree.nodes.forEach(node =&gt; walkTree(node, walker, tree, depth + 1));
}
walker(tree, parent, depth);
};
const walkForest = (forest, walker) =&gt; {
forest.forEach(tree =&gt; walkTree(tree, walker));
};
const childMatches = (node, predicate) =&gt;
predicate(node) || node.nodes.some(child =&gt; childMatches(child, predicate));
const data = [{
key: &quot;id1&quot;,
name: &quot;Category 1&quot;,
curr: 0,
total: 0,
nodes: [{
key: &quot;id2&quot;,
name: &quot;Applications&quot;,
curr: 20,
total: 30,
nodes: [{
key: &quot;id3&quot;,
name: &quot;Gaming&quot;,
curr: 5,
total: 10,
nodes: []
}, {
key: &quot;id4&quot;,
name: &quot;Operating System&quot;,
curr: 15,
total: 20,
nodes: []
}]
}]
},
{
key: &quot;id5&quot;,
name: &quot;Category 2&quot;,
curr: 0,
total: 0,
nodes: [{
key: &quot;id6&quot;,
name: &quot;Sub Category&quot;,
curr: 12,
total: 48,
nodes: [{
key: &quot;id7&quot;,
name: &quot;Inside Sub&quot;,
curr: 12,
total: 48,
nodes: []
}]
}]
},
{
key: &quot;id8&quot;,
name: &quot;Last One&quot;,
curr: 0,
total: 0,
nodes: []
}
];
main();

<!-- language: lang-css -->

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

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年5月22日 21:03:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76306504.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定