Construiește JSON dintr-un array JavaScript recursiv


Vreau să construiesc un obiect JSON dintr-un tablou returnat de o cerere HTTP, tabloul meu actual arată astfel:

[{
    Description: "Product"
    IsInstanciable: false
    IsMasked: false
    Name: "ProductBase"
    Subclasses: [{
      Description: "Product2"
      IsInstanciable: false
      IsMasked: false
      Name: "ProductBase2",
      Count: 5,
      Subclasses:[]
    },
    {
      Description: "Product3"
      IsInstanciable: false
      IsMasked: false
      Name: "ProductBase3",
      Count: 4,
      Subclasses:[],
    }]
},
{
    Description: "Product4"
    IsInstanciable: false
    IsMasked: false
    Name: "ProductBase4",
    Count: '...',
    Subclasses: [...]
}

Vreau să creez un obiect JSON recursiv din array-ul de mai sus. Va arăta astfel:

[
  {
    name: 'Product',
    Count: 9,
    children: [
      {name: 'Product2'},
      {name: 'Product3'},
    ]
  }, {
    name: 'Product4',
    children: [
      {
        name: '...',
        Count: 'Sum of Count in all children by level'
        children: [
          {name: '...'},
          {name: '...'},
        ]
      }
    ]
  },
];

Iată funcția mea recursivă în TypeScript, dar nu funcționează așa cum mă aștept. Cum pot să o repar?

recursive(data, stack: TreeNode[]) {
    let elt: TreeNode = {name:'', children: []}
    if(data.Subclasses.length > 0) {
      elt.name = data.Description;
      data.Subclasses.forEach(element => {
        elt.children.push({name: element.Description});
        this.recursive(element, stack);
      });
    }else {
      elt.name = data.Description;
    }
    stack.push(elt);
  }

Răspuns #1

Poți folosi funcția map împreună cu funcția recursivă astfel:

function MapObject(object) {
  if(!object || object.length < 0) return [];

  return object.map(obj => { return {
      name: obj.Description,
      children: MapObject(obj.Subclasses)
  }});
}

Urmează un exemplu de lucru complet:

var example = [{
    Description: "Product",
    IsInstanciable: false,
    IsMasked: false,
    Name: "ProductBase",
    Subclasses: [{
      Description: "Product2",
      IsInstanciable: false,
      IsMasked: false,
      Name: "ProductBase2",
      Subclasses:[]
    },
    {
      Description: "Product3",
      IsInstanciable: false,
      IsMasked: false,
      Name: "ProductBase3",
      Subclasses:[]
    }]
},
{
    Description: "Product4",
    IsInstanciable: false,
    IsMasked: false,
    Name: "ProductBase4"
}]

function MapObject(object) {
  if(!object || object.length < 0) return [];
  
  return object.map(obj => { return {
      name: obj.Description,
      children: MapObject(obj.Subclasses)
  }});
}

console.log(MapObject(example));

Răspunsul #2

Aș împărți acest lucru în câteva funcții separate cu responsabilități clare:

const sum = (ns) => 
  ns .reduce ((a, b) => a + Number (b), 0)

const getCount = (product) => 
  (product .Count || 0) + sum ((product .Subclasses || []) .map (getCount))

const extract = (product) => 
  ({
    name: product .Name,
    count: getCount (product),
    children: product .Subclasses .map (extract)
  })

const extractAll = (products) => 
  products .map (extract)

const products = [{"Description": "Product", "IsInstanciable": false, "IsMasked": false, "Name": "ProductBase", "Subclasses": [{"Count": 5, "Description": "Product2", "IsInstanciable": false, "IsMasked": false, "Name": "ProductBase2", "Subclasses": []}, {"Count": 4, "Description": "Product3", "IsInstanciable": false, "IsMasked": false, "Name": "ProductBase3", "Subclasses": []}]}, {"Count": 3, "Description": "Product4", "IsInstanciable": false, "IsMasked": false, "Name": "ProductBase4", "Subclasses": []}]

console .log (
  extractAll (products)
)

(Rețineți că am schimbat majusculele proprietății de ieșire count. Mi s-a părut pur și simplu mai consistent cu name și children.)

Recurgem prin obiect pentru a obține proprietatea Count și recurgem separat pentru a obține restul obiectului. Deși ar putea exista o modalitate de a le combina, m-aș aștepta ca codul să fie semnificativ mai complex.

Rețineți că am presupus că toate proprietățile Count sunt de fapt numerice, deși exemplul vostru de mai sus include un șir de caractere. Dacă aveți valori precum "3", atunci getCount va trebui să fie puțin mai sofisticat.