获取JavaScript中嵌套数组的子元素。

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

how to get the children of a deeply nested array in js

问题

以下是您要翻译的内容:

我有这些数据
const data = [
  {
    name: "Car",
    id: "19",
    count: "20",
    depth: "1",
    children: [
      {
        name: "Wheel",
        id: "22",
        count: "3",
        depth: "2",
        children: [
          {
            name: "Engine",
            id: "101",
            count: "1",
            depth: "3",
            children: [
              {
                name: "Engine and Brakes",
                id: "344",
                count: "1",
                depth: "4",
                children: []
              }
            ]
          }
        ]
      }
    ]
  },
  {
    name: "Bike",
    id: "3",
    count: "12",
    depth: "1",
    children: [
      {
        name: "SpeedBike",
        id: "4",
        count: "12",
        depth: "2",
        children: []
      }
    ]
  }
];

我想要按照以下方式传递多个类别 ID:['101', '3'],并且只能获取传递的类别 ID 的直接子项,应该看起来像这样:

[
  {
     name: "Engine and Brakes",
     id: "344",
     count: "1",
  },
  {
    name: "SpeedBike",
    id: "4",
    count: "12",
   }
]

如果没有传递类别 ID,则希望能够默认查看父项和直接子项。如下所示:

[
 {  
    name: "Car",
    id: "19",
    count: "20"
 },
 {
    name: "Wheel",
    id: "22",
    count: "3"
 },
 {
    name: "Bike",
    id: "3",
    count: "12",
 },
 {
    name: "SpeedBike",
    id: "4",
    count: "12"
 }
]

如果传递的类别 ID 没有子项,我希望返回一个空数组:

[]

我想避免使用 forforeachwhile。如何实现这一点?我尝试使用 mapfilter,但没有成功。有人可以帮忙吗?哪种方法最好?

我正在使用 JavaScript 和 TypeScript。

嵌套数组可能会有多个深层级。

英文:

I have this data

  const data = [
{
name: "Car",
id: "19",
count: "20",
depth: "1",
children: [
{
name: "Wheel",
id: "22",
count: "3",
depth: "2",
children: [
{
name: "Engine",
id: "101",
count: "1",
depth: "3",
children: [
{
name: "Engine and Brakes",
id: "344",
count: "1",
depth: "4",
children: []
}
]
}
]
}
]
},
{
name: "Bike",
id: "3",
count: "12",
depth: "1",
children: [
{
name: "SpeedBike",
id: "4",
count: "12",
depth: "2",
children: []
}
]
}
];

I want to pass in multiple category ids as follows ['101', '3'] and be able to only get the direct children of the passed category ids which should look like this:


[
{
name: "Engine and Brakes",
id: "344",
count: "1",
},
{
name: "SpeedBike",
id: "4",
count: "12",
}
]

If no category id is passed I want to be able to see the parent and the direct children as default. like below:

[
{  
name: "Car",
id: "19",
count: "20"
},
{
name: "Wheel",
id: "22",
count: "3"
},
{
name: "Bike",
id: "3",
count: "12",
},
{
name: "SpeedBike",
id: "4",
count: "12"
}
]

If the category id passed does not have children I want to return an empty array.:

[]

I want to avoid using for foreach and while. How can I achieve this? I have tried using map and filter but no luck. Can someone please help? What is the best approach to this?

I am using js and ts.

The nested array can be deep with multiple deep levels.

答案1

得分: 2

以下是您要翻译的内容:

There is no built-in functions to do that. Instead, there are two approaches that we can take: iterative and recursive.

The recursive approach requires O(logN) extra space for call stack size; thus, we will use the iterative approach.

Algorithm:

  • If category ids are provided:
    • Populate stack with categories of the first level
    • While the stack is not empty:
      • Pop category from the stack
      • If category id is in the desired ids array:
        • Map through the category's children and retrieve the desired properties
      • Push children of the category to stack
  • else:
    • Loop through the first level.
    • Push the parent and children of the parent.

Type for category:

type Category = {
name: string;
id: string;
count: string;
depth: string;
children: Category[];
};

Implementation:

const getCategoriesChildren = (
categoryIds: Category['id'][],
categories: Category[],
) => {
const foundChildren: Pick<Category, 'id' | 'count' | 'name'>[] = [];
if (categoryIds.length === 0) {
return categories.reduce<Pick<Category, 'id' | 'count' | 'name'>[]>(
(acc, category) => {
acc.push(mapCategory(category), ...category.children.map(mapCategory));
return acc;
},
[],
);
}
const stack = [...categories];
while (stack.length) {
const category = stack.pop();
if (!category) continue;
if (categoryIds.includes(category.id)) {
foundChildren.push(
...category.children.map((childCategory) => ({
name: childCategory.name,
id: childCategory.id,
count: childCategory.count,
})),
);
}
stack.push(...category.children);
}
return foundChildren;
};

Usage:

// [{
//   "name": "SpeedBike",
//   "id": "4",
//   "count": "12"
// }, {
//   "name": "Engine and Brakes",
//   "id": "344",
//   "count": "1"
// }] 
console.log(getCategoriesChildren(['101', '3'], data));
// [{
//   "name": "Car",
//   "id": "19",
//   "count": "20"
// }, {
//   "name": "Wheel",
//   "id": "22",
//   "count": "3"
// }, {
//   "name": "Bike",
//   "id": "3",
//   "count": "12"
// }, {
//   "name": "SpeedBike",
//   "id": "4",
//   "count": "12"
// }]
console.log(getCategoriesChildren([], data));

playground

英文:

There is no built-in functions to do that. Instead, there are two approaches that we can take: iterative and recursive.

The recursive approach requires O(logN) extra space for call stack size; thus, we will use the iterative approach.

Algorithm:

  • If category ids are provided:
    • Populate stack with categories of the first level
    • While the stack is not empty:
      • Pop category from the stack
      • If category id is in the desired ids array:
        • Map through the category's children and retrieve the desired properties
      • Push children of the category to stack
  • else:
    • Loop through the first level.
    • Push the parent and children of the parent.

Type for category:

type Category = {
name: string;
id: string;
count: string;
depth: string;
children: Category[];
};

Implementation:

const getCategoriesChildren = (
categoryIds: Category[&#39;id&#39;][],
categories: Category[],
) =&gt; {
const foundChildren: Pick&lt;Category, &#39;id&#39; | &#39;count&#39; | &#39;name&#39;&gt;[] = [];
if (categoryIds.length === 0) {
return categories.reduce&lt;Pick&lt;Category, &#39;id&#39; | &#39;count&#39; | &#39;name&#39;&gt;[]&gt;(
(acc, category) =&gt; {
acc.push(mapCategory(category), ...category.children.map(mapCategory));
return acc;
},
[],
);
}
const stack = [...categories];
while (stack.length) {
const category = stack.pop();
if (!category) continue;
if (categoryIds.includes(category.id)) {
foundChildren.push(
...category.children.map((childCategory) =&gt; ({
name: childCategory.name,
id: childCategory.id,
count: childCategory.count,
})),
);
}
stack.push(...category.children);
}
return foundChildren;
};

Usage:

// [{
//   &quot;name&quot;: &quot;SpeedBike&quot;,
//   &quot;id&quot;: &quot;4&quot;,
//   &quot;count&quot;: &quot;12&quot;
// }, {
//   &quot;name&quot;: &quot;Engine and Brakes&quot;,
//   &quot;id&quot;: &quot;344&quot;,
//   &quot;count&quot;: &quot;1&quot;
// }] 
console.log(getCategoriesChildren([&#39;101&#39;, &#39;3&#39;], data));
// [{
//   &quot;name&quot;: &quot;Car&quot;,
//   &quot;id&quot;: &quot;19&quot;,
//   &quot;count&quot;: &quot;20&quot;
// }, {
//   &quot;name&quot;: &quot;Wheel&quot;,
//   &quot;id&quot;: &quot;22&quot;,
//   &quot;count&quot;: &quot;3&quot;
// }, {
//   &quot;name&quot;: &quot;Bike&quot;,
//   &quot;id&quot;: &quot;3&quot;,
//   &quot;count&quot;: &quot;12&quot;
// }, {
//   &quot;name&quot;: &quot;SpeedBike&quot;,
//   &quot;id&quot;: &quot;4&quot;,
//   &quot;count&quot;: &quot;12&quot;
// }]
console.log(getCategoriesChildren([], data));

playground

huangapple
  • 本文由 发表于 2023年5月17日 17:27:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76270550.html
匿名

发表评论

匿名网友

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

确定