Generate an array in function of another without bottlenecks

3

I have the following array of objects:

[
   { 
      id: "1", 
      name: "ProdutoA",
      categorias: [
          {idCat: 1, name: "CategoriaA"},
          {idCat: 2, name: "CategoriaB"}
      ] 
   },
   { 
      id: "2", 
      name: "ProdutoB",
      categorias: [
          {idCat: 1, name: "CategoriaA"}
      ] 
   }
]

From this array of objects, I need to generate another array with the following structure:

[
   {idCat: 1, name: "CategoriaA", products: ["ProdutoA","ProdutoB"]},
   {idCat: 2, name: "CategoriaB", products: ["ProdutoA"]}
]

I do not know how to do this using the best JavaScript practices, only using the for cycle, but I do not know if it will be performative when the first array is too large.

How to generate the second array as a function of the first?

Note : The initial array of objects will always be consistent and produced in this way through a framework. Therefore, all elements with the same idCat will always have the same name , so it is not necessary to worry about a hypothetical case where two elements with the same idCat have name s different.     

asked by anonymous 21.10.2015 / 18:42

2 answers

3

Since category IDs are simple numbers, an object mapping ID to structure should suffice:

function converter(produtos) {
  var map = {};
  
  produtos.forEach(function(produto) {
      produto.categorias.forEach(function(cat) {
          if ( !map[cat.idCat] )
              map[cat.idCat] = { idCat:cat.idCat, name:cat.name, products:[] };
          map[cat.idCat].products.push(produto.name);
      });
  });
  
  var ret = [];
  for ( var p in map )
    ret.push(map[p]);
  // Opcional: ordena o retorno
  return ret;
}

var entrada = [
   { 
      id: "1", 
      name: "ProdutoA",
      categorias: [
          {idCat: 1, name: "CategoriaA"},
          {idCat: 2, name: "CategoriaB"}
      ] 
   },
   { 
      id: "2", 
      name: "ProdutoB",
      categorias: [
          {idCat: 1, name: "CategoriaA"}
      ] 
   }
];
document.body.innerHTML += "<pre>" + JSON.stringify(converter(entrada), null, 4) + "<pre>";
    
21.10.2015 / 19:15
1

Look, I think the best way is to use a little Prototype and create two lists (Products and Category) and create references between them.

var estrutura = [
  { 
    id: "1", 
    name: "ProdutoA",
    categorias: [
      {idCat: 1, name: "CategoriaA"},
      {idCat: 2, name: "CategoriaB"}
    ] 
  },
  { 
    id: "2", 
    name: "ProdutoB",
    categorias: [
      {idCat: 1, name: "CategoriaA"}
    ] 
  }
];

var produtos = {};
var categorias = {};

var Produto = function (item) {
  this.id = item.id;
  this.name = item.name;
  this.categorias = [];
}

var Categoria = function (subitem) {
  this.idCat = subitem.idCat;
  this.name = subitem.name;
  this.produtos = [];
}

estrutura.forEach(function (item, indice) {
  var produto = new Produto(item);
  produtos[item.id] = produto;

  item.categorias.forEach(function (subitem, indice) {
    var categoria = categorias[subitem.idCat];
    if (!categoria) {
      categoria = new Categoria(subitem);
      categorias[subitem.idCat] = categoria;
    }
    categoria.produtos.push(produto);
    produto.categorias.push(categoria);
  });
});

console.log(categorias, produtos);

In this case, you can access the product or category by the ID:

var produto = produtos[1]; //retorna o ProdutoA;
var categoria = categoria[1]; //retorna a CategoriaA;

as well as being able to navigate within properties:

var irmaos = produtos[2].categorias[1].produtos; //todos os produtos da categoriaA
    
21.10.2015 / 19:31