簡體   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