Mam tablicę obiektów, która zawiera inną tablicę z obiektami. Zagnieżdżenie jest głębokie na cztery poziomy. Struktura tablicy jest następująca:

[
  {
    title: 'Title',
    type: 'section',
    links: [
      {
        label: 'Label',
        id: 'id_1',
        links: [
          {
            title: 'Title',
            type: 'section',
            links: [
              {
                label: 'Label',
                id: 'id_2',
                links: [
                  {
                    label: 'Label',
                    id: 'id_3',
                    links: [],
                  }
                ]
              }
            ]
          },
          {
            title: 'Other title',
            type: 'section',
            links: [
              {
                label: 'Label',
                id: 'id_4',
                links: [],
              }
            ]
          }
        ]
      }
    ]
  }
]

Chcę mieć spłaszczoną tablicę z identyfikatorami tablic łączy, które zawierają linki (są rodzicami podmenu). Tak więc pożądany wynik jest taki: ["id_1", "id_2"]

Próbowałem uzyskać wynik za pomocą tej funkcji pobranej z MDN:

flatDeep(arr, d = 1) {
  return d > 0
    ? arr.reduce((acc, val) =>
      acc.concat(Array.isArray(val.links)
        ? this.flatDeep(val.links, d - 1)
        : val.links), [])
    : arr.slice();
}

To daje mi pustą tablicę.

2
Gert-Jan Kooijmans 31 marzec 2020, 20:01

5 odpowiedzi

Najlepsza odpowiedź

Możesz otrzymać płaską tablicę z rekurencją i sprawdzeniem id pod kątem brakującej właściwości.

const
    getId = ({ id, links }) => [
        ...(id === undefined ? [] : [id]),
        ...links.flatMap(getId)
    ],
    data = [{ title: 'Title', type: 'section', links: [{ label: 'Label', id: 'id_1', links: [{ title: 'Title', type: 'section', links: [{ label: 'Label', id: 'id_2', links: [{ label: 'Label', id: 'id_3', links: [] }] }] }, { title: 'Other title', type: 'section', links: [{ label: 'Label', id: 'id_4', links: [] }] }] }] }],
    result = data.flatMap(getId);

console.log(result);
0
Nina Scholz 31 marzec 2020, 17:23

Myślę, że funkcja rekurencyjna uprości. (rekurencyjnie poszukaj tablicy lists i wepchnij id do res).

const data = [
  {
    title: "Title",
    type: "section",
    links: [
      {
        label: "Label",
        id: "id_1",
        links: [
          {
            title: "Title",
            type: "section",
            links: [
              {
                label: "Label",
                id: "id_2",
                links: [
                  {
                    label: "Label",
                    id: "id_3",
                    links: []
                  }
                ]
              }
            ]
          },
          {
            title: "Other title",
            type: "section",
            links: [
              {
                label: "Label",
                id: "id_4",
                links: []
              }
            ]
          }
        ]
      }
    ]
  }
];

const res = [];

const ids = data => {
  data.forEach(item => {
    if ("id" in item) {
      res.push(item.id);
    }
    if (item.links) {
      ids(item.links);
    }
  });
};

ids(data);
console.log(res);
0
sivako 1 kwiecień 2020, 04:26

Oto wersja nierekurencyjna.

const data = [{title:'Title',type:'section',links:[{label:'Label',id:'id_1',links:[{title:'Title',type:'section',links:[{label:'Label',id:'id_2',links:[{label:'Label',id:'id_3',links:[]}]}]},{title:'Other title',type:'section',links:[{label:'Label',id:'id_4',links:[]}]}]}]}];

const stack = data.slice();
const result = [];

let obj;
while (obj = stack.shift()) {
  if ("id" in obj && obj.links.length > 0) result.push(obj.id);
  stack.push(...obj.links);
}

console.log(result);

Najpierw wykorzystuje się oddech, ale można go łatwo zmienić na głębokość. Będziesz musiał tylko zmienić wywołanie stack.push na stack.unshift.

Aby uzyskać bardziej szczegółowe wyjaśnienie tych dwóch, zobacz Breadth First Vs Depth First.

0
3limin4t0r 31 marzec 2020, 18:45
var array = JSON.parse('[{"title":"Title","type":"section","links":[{"label":"Label","id":"id_1","links":[{"title":"Title","type":"section","links":[{"label":"Label","id":"id_2","links":[{"label":"Label","id":"id_3","links":[]}]}]},{"title":"Other title","type":"section","links":[{"label":"Label","id":"id_4","links":[]}]}]}]}]');


arr = [];
 while(array.length != 0) {
  var ob1 = array.splice(0,1)[0];
  for(var ob2 of ob1.links) {
    if (ob2.links.length !== 0) {
      arr.push(ob2.id);
      array = array.concat(ob2.links);
    }
  }
 }

console.log(arr);

Oto wynik, o który prosiłeś:

[
  "id_1",
  "id_2"
]
0
Tanmay_vijay 31 marzec 2020, 17:20

Użyj Array.flatMap(). Zniszcz każdy obiekt i użyj pustej tablicy jako domyślnej dla brakujących wartości id. Połącz id i wynik rekursywnego spłaszczania linków.

const flattenIds = arr => arr.flatMap(({ id = [], links }) => 
  [].concat(id, flattenIds(links))
);
    
const data = [{ title: 'Title', type: 'section', links: [{ label: 'Label', id: 'id_1', links: [{ title: 'Title', type: 'section', links: [{ label: 'Label', id: 'id_2', links: [{ label: 'Label', id: 'id_3', links: [] }] }] }, { title: 'Other title', type: 'section', links: [{ label: 'Label', id: 'id_4', links: [] }] }] }] }];

const result = flattenIds(data);

console.log(result);
0
Ori Drori 31 marzec 2020, 17:32