繁体   English   中英

从 Typescript/Javascript 中的平面数组构建树数组(3 维)

[英]Build a tree array (3 dimensional) from a flat array in Typescript/Javascript

我有这种格式的传入数据:

const worldMap = [
  {
    "name": "Germany",
    "parentId": null,
    "type": "Country",
    "value": "country:unique:key:1234",
    "id": "1",
  },
  {
    "name": "North Rhine",
    "parentId": "1",
    "type": "State",
    "value": "state:unique:key:1234",
    "id": "2",
  },
  {
    "name": "Berlin",
    "parentId": "1",
    "type": "State",
    "value": "state:unique:key:1234",
    "id": "3",
  },  
  {
    "name": "Dusseldorf",
    "parentId": "2",
    "type": "city",
    "value": "city:unique:key:1234",
    "id": "4",
  },
   {
    "name": "India",
    "parentId": null,
    "type": "Country",
    "value": "country:unique:key:1234",
    "id": "5",
  }, 
];

我希望输出是这样的:

[
   {
   label: "Germany",
   value: "country:unique:key:1234",
   subs: [
    {
        label: "North Rhine",
        value: "state:unique:key:1234",
        subs: [
            {
                label: "Dusseldorf",
                value: "city:unique:key:1234",
            }
        ]
    },
    {
       label: "Berlin",
       value: "state:unique:key:1234",
    }
   ]
   }
   ,
   {
       "label": "India",
       "value": "country:unique:key:1234"
   }
]

基本上,它是一个三维阵列,第一层是国家、第二州和第三城市。 我尝试了以下代码:

let tempCountries = [];

worldMap.map((world) => {
  if (world.parentId == null && world.type == "Country") {
    tempCountries.push({label: world.name, value: world.value, id: world.id});
  }
});


tempCountries.map((tempCountry) => {
  const states = worldMap.find((x) => x.parentId == tempCountry.id);
  console.log("=== states ===", states);
  if (states !== undefined) {
      tempCountries.find((x)=>x.id == tempCountry.id).children.push(states)
  }
});

但是上面的代码可以工作到第二级,并且不会将城市添加到州。 任何人都可以帮我实现这一目标吗?

非常感谢!

它看起来有点乱,但似乎有效。

基本思想是生成 id 到世界对象值的映射。 从基本情况“国家”开始很容易。 下一种情况是“state”,它使用parentId字段来匹配国家/地区键。 这也很简单。 第三层“城市”很棘手,因为城市对象只引用它们的父状态对象 id,因此需要通过每个国家对象的subs对象搜索匹配的parentId

一旦世界数组被完全处理成世界映射对象,它需要减少回仅值数组。

一个限制是假设在世界数组中所有父对象都将任何嵌套子对象之前定义。 IE 一个城市的州已经被看到和处理过,一个州的国家已经被看到和处理过。

const buildWorld = (worldArray) => {
  const builtObj = worldArray.reduce((worldObj, obj) => {
    switch (obj.type) {
      case "Country":
        return {
          ...worldObj,
          [obj.id]: {
            label: obj.name,
            value: obj.value
          }
        };

      case "State":
        return {
          ...worldObj,
          [obj.parentId]: {
            ...worldObj[obj.parentId],
            subs: {
              ...worldObj[obj.parentId].subs,
              [obj.id]: {
                label: obj.name,
                value: obj.value
              }
            }
          }
        };

      case "city":
        const [countryId] = Object.entries(worldObj).find(([key, country]) =>
         country.subs[obj.parentId]
        );
        return {
          ...worldObj,
          [countryId]: {
            ...worldObj[countryId],
            subs: {
              ...worldObj[countryId].subs,
              [obj.parentId]: {
                ...worldObj[countryId].subs[obj.parentId],
                subs: [
                  ...worldObj[countryId].subs[obj.parentId]?.subs ?? [],
                  {
                    label: obj.name,
                    value: obj.value,
                  }
                ]
              }
            }
          }
        };

      default:
        return worldObj;
    }
  }, {});

  

  return Object.values(builtObj).map(country => ({
    ...country,
    ...country.subs ? {subs: Object.values(country.subs)} : {}
  }));
};

 const worldMap = [ { name: "Germany", parentId: null, type: "Country", value: "country:unique:key:1234", id: "1" }, { name: "North Rhine", parentId: "1", type: "State", value: "state:unique:key:1234", id: "2" }, { name: "Berlin", parentId: "1", type: "State", value: "state:unique:key:1234", id: "3" }, { name: "Dusseldorf", parentId: "2", type: "city", value: "city:unique:key:1234", id: "4" }, { name: "India", parentId: null, type: "Country", value: "country:unique:key:1234", id: "5" } ]; const buildWorld = (worldArray) => { const builtObj = worldArray.reduce((worldObj, obj) => { switch (obj.type) { case "Country": return { ...worldObj, [obj.id]: { label: obj.name, value: obj.value } }; case "State": return { ...worldObj, [obj.parentId]: { ...worldObj[obj.parentId], subs: { ...worldObj[obj.parentId].subs, [obj.id]: { label: obj.name, value: obj.value } } } }; case "city": const [countryId] = Object.entries(worldObj).find(([key, country]) => country.subs[obj.parentId] ); return { ...worldObj, [countryId]: { ...worldObj[countryId], subs: { ...worldObj[countryId].subs, [obj.parentId]: { ...worldObj[countryId].subs[obj.parentId], subs: [ ...worldObj[countryId].subs[obj.parentId]?.subs ?? [], { label: obj.name, value: obj.value, } ] } } } }; default: return worldObj; } }, {}); return Object.values(builtObj).map(country => ({ ...country, ...country.subs ? {subs: Object.values(country.subs)} : {} })); }; console.log(buildWorld(worldMap));

您可以使用递归解决方案:

function convertToTree(layer, parentId = null) {
    const vertex = new Map(), others = [];

    layer.forEach(item => {
        if (item.parentId === parentId) {
            vertex.set(item.id, { label: item.name, value: item.value });
        } else {
            others.push(item);
        }
    });

    for (const vertexId of vertex.keys()) {
        const subs = convertToTree(others, vertexId);
        if (subs.length) {
            vertex.get(vertexId).subs = subs;
        }
    }

    return [...vertex.values()];
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM