Angular项目中如何将列表转换为Primeng TreeSelect所需树形结构?
如何将扁平列表转换为PrimeNG TreeSelect所需的树形结构?
在Angular项目中,需要把扁平的合同列表转换为三层树形结构(国家 -> 产品类型 -> 交付周期),以适配PrimeNG的TreeSelect组件。
初始数据结构
initialDataStructure = [ { "country": "GERMANY", "productType": "BASE", "deliveryPeriod": "MONTH"}, { "country": "GERMANY", "productType": "BASE", "deliveryPeriod": "YEAR"}, { "country": "GERMANY", "productType": "PEAK", "deliveryPeriod": "MONTH"}, { "country": "GERMANY", "productType": "PEAK", "deliveryPeriod": "YEAR"}, { "country": "AUSTRIA", "productType": "BASE", "deliveryPeriod": "MONTH"}, { "country": "AUSTRIA", "productType": "BASE", "deliveryPeriod": "YEAR"}, { "country": "AUSTRIA", "productType": "PEAK", "deliveryPeriod": "MONTH"}, { "country": "AUSTRIA", "productType": "PEAK", "deliveryPeriod": "YEAR"}, ]
尝试过的代码(未达预期)
for (var i = 0, len = this.listContracts.length, p; i < len; i++) { // faster than .forEach p = this.listContracts[i]; if (this.grouped[p.country] === undefined) // twice faster then hasOwnProperty this.grouped[p.country] ={} if (this.grouped[p.country][p.productType] === undefined) this.grouped[p.country][p.productType] ={} if (this.grouped[p.country][p.productType][p.deliveryPeriod] === undefined) this.grouped[p.country][p.productType][p.deliveryPeriod]=[] this.grouped[p.country][p.productType][p.deliveryPeriod].push(p); // groupby is HERE xD }
期望的树形结构
expectedDataStructure = [ { label: "GERMANY", children: [ { label: "BASE", children: [ { label: "MONTH", children: [{ "country": "GERMANY", "productType": "BASE", "deliveryPeriod": "MONTH"}] }, { label: "YEAR", children: [{ "country": "GERMANY", "productType": "BASE", "deliveryPeriod": "YEAR"}] } ] }, { label: "PEAK", children: [ { label: "MONTH", children: [{ "country": "GERMANY", "productType": "PEAK", "deliveryPeriod": "MONTH"}] }, { label: "YEAR", children: [{ "country": "GERMANY", "productType": "PEAK", "deliveryPeriod": "YEAR"}] } ] }, ] }, { label: "AUSTRIA", children: [ { label: "BASE", children: [ { label: "MONTH", children: [{ "country": "AUSTRIA", "productType": "BASE", "deliveryPeriod": "MONTH"}] }, { label: "YEAR", children: [{ "country": "AUSTRIA", "productType": "BASE", "deliveryPeriod": "YEAR"}] } ] }, { label: "PEAK", children: [ { label: "MONTH", children: [{ "country": "AUSTRIA", "productType": "PEAK", "deliveryPeriod": "MONTH"}] }, { label: "YEAR", children: [{ "country": "AUSTRIA", "productType": "PEAK", "deliveryPeriod": "YEAR"}] } ] }, ] }, ]
解决方案
方法1:先分组再转换结构
先通过reduce按层级分组,再将嵌套对象转换为TreeSelect需要的label+children结构,逻辑清晰易读:
function convertToTreeStructure(data: any[]): any[] { // 第一步:按国家->产品类型->交付周期分组 const grouped = data.reduce((acc, item) => { if (!acc[item.country]) acc[item.country] = {}; if (!acc[item.country][item.productType]) acc[item.country][item.productType] = {}; if (!acc[item.country][item.productType][item.deliveryPeriod]) { acc[item.country][item.productType][item.deliveryPeriod] = []; } acc[item.country][item.productType][item.deliveryPeriod].push(item); return acc; }, {}); // 第二步:将分组对象转换为树形结构 return Object.entries(grouped).map(([country, productTypes]) => ({ label: country, children: Object.entries(productTypes).map(([productType, deliveryPeriods]) => ({ label: productType, children: Object.entries(deliveryPeriods).map(([period, items]) => ({ label: period, children: items })) })) })); } // 使用示例 const treeData = convertToTreeStructure(this.initialDataStructure);
方法2:一次遍历直接构建树形
直接在遍历过程中查找或创建节点,减少一次转换步骤,数据量较大时更高效:
function convertToTreeStructureDirectly(data: any[]): any[] { const tree: any[] = []; data.forEach(item => { // 查找或创建国家节点 let countryNode = tree.find(node => node.label === item.country); if (!countryNode) { countryNode = { label: item.country, children: [] }; tree.push(countryNode); } // 查找或创建产品类型节点 let productNode = countryNode.children.find(node => node.label === item.productType); if (!productNode) { productNode = { label: item.productType, children: [] }; countryNode.children.push(productNode); } // 查找或创建交付周期节点 let periodNode = productNode.children.find(node => node.label === item.deliveryPeriod); if (!periodNode) { periodNode = { label: item.deliveryPeriod, children: [] }; productNode.children.push(periodNode); } // 添加当前条目到节点 periodNode.children.push(item); }); return tree; } // 使用示例 const treeData = convertToTreeStructureDirectly(this.initialDataStructure);
可选:TypeScript类型支持
如果需要强类型约束,可以定义树形节点接口:
interface TreeNode { label: string; children: (TreeNode | Record<string, any>)[]; }
内容的提问来源于stack exchange,提问作者Ahmed Z.
相关产品推荐
相关产品推荐

