Узел Js - Свести массив объектов

У меня есть такой массив

var data = [
    {
        family: "Fam A",
        category: "Cat A",
        products: [
            {
                name: "Name A1",
                style: "Style A1"
            },
            {
                name: "Name A2",
                style: "Style A2"
            }
        ]
    },
    {
        family: "Fam B",
        category: "Cat B",
        products: [
            {
                name: "Name B1",
                style: "Style B1"
            },
            {
                name: "Name B2",
                style: "Style B2"
            }
        ]
    }
]; 

Я хочу изменить внутренние объекты, как показано ниже

var data = [
    {family:"Fam A", category: "Cat A", name: "Name A1", style:"Style A1"},
    {family:"Fam A", category: "Cat A", name: "Name A2", style:"Style A2"},
    {family:"Fam B", category: "Cat B", name: "Name B1", style:"Style B1"},
    {family:"Fam B", category: "Cat B", name: "Name B2", style:"Style B2"}
]  

Я пытался использовать карту и forEach, которые я нашел в других сообщениях, но не получил ничего, чтобы работать.

var flattened = data.products.map(x => Object.assign(x, { productDetails: data.products }))

function getList(data, arrayKey, arrayName) {
    data[arrayKey].forEach(function(element) {
        element[arrayName] = data[arrayName];
    });
    return data[arrayKey];
}

Идеальное решение было бы в состоянии обрабатывать динамические нет вложений, но не нужно двигаться дальше.

Заранее спасибо за помощь новому разработчику!

Всего 3 ответа


Вы можете взять Array#flatMap с вложенным отображением.

var data = [{ family: "Fam A", category: "Cat A", products: [{ name: "Name A1", style: "Style A1" }, { name: "Name A2", style: "Style A2" }] }, { family: "Fam B", category: "Cat B", products: [{ name: "Name B1", style: "Style B1" }, { name: "Name B2", style: "Style B2" }] }],
    flat = data.flatMap(({ products, ...o }) => products.map(p => ({ ...o, ...p })));

console.log(flat);
.as-console-wrapper { max-height: 100% !important; top: 0; }


Могу предложить общее (рекурсивное) решение:

var data = [
    {
        family: "Fam A",
        category: "Cat A",
        products: {
            somekey: 'someval',
            items : {
                type: 'A type',
                list: [{name: "Name A1", style: "Style A1"},
                      {name: "Name A2", style: "Style A2"}]
            }
        }
    },
    {
        family: "Fam B",
        category: "Cat B",
        products: {
            somekey: 'someval',
            items :[{name: "Name B1", style: "Style B1"},
                   {name: "Name B2", style: "Style B2"}]
        }
    }
]; 

const output = data.reduce((aggArr, child) => {   
  function recursiveFlat(currChild, currParent){
    currParent = currParent || {};
    return Object.entries(currChild).reduce((aggChildArr,[key,val]) => {
      let tempObj = {...currParent, ...currChild}
      if (val instanceof Array){
        delete tempObj[key];
        val.forEach(item => {
          aggChildArr.push({...tempObj,...item});
        })
      }else if(val instanceof Object){
        delete tempObj[key];
        aggChildArr = [...aggChildArr, ...recursiveFlat(val, tempObj)];
      }
      return aggChildArr;
    },[])
  }
  const flatArr = recursiveFlat(child);
  flatArr.forEach(item => aggArr.push(item));
  return aggArr;
},[])

console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }

обновить , пытаясь взять красивое .flatMap() и сделать его универсальным и рекурсивным:

const data = [{ family: "Fam A", category: "Cat A", items: { types: {type: 'A1-2', products: [{ name: "Name A1", style: "Style A1" }, { name: "Name A2", style: "Style A2" }]}, somekey: 'example' } }, { family: "Fam B", category: "Cat B", products: [{ name: "Name B1", style: "Style B1" }, { name: "Name B2", style: "Style B2" }] }];
    
function flatten(data){
  const flat = data.flatMap((obj) => {
    function innerFlatten(obj, parentObj){
      parentObj = parentObj || {};
      for (key in obj){
        if (obj[key] instanceof Array){
          const tempArr = obj[key];
          delete obj[key];
          return tempArr.map(p => ({...parentObj, ...obj, ...p }) ) 
        }else if (obj[key] instanceof Object){
          const tempObj = obj[key];
          delete obj[key];
          return innerFlatten(tempObj, {...parentObj, ...obj});
        }  
      }      
    }
    return innerFlatten(obj);    
  });
  return flat;
}

console.log(flatten(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }


Вы можете использовать reduce , быстрее и лучше.

var data = [{"family":"Fam A","category":"Cat A","products":[{"name":"Name A1","style":"Style A1"},{"name":"Name A2","style":"Style A2"}]},{"family":"Fam B","category":"Cat B","products":[{"name":"Name B1","style":"Style B1"},{"name":"Name B2","style":"Style B2"}]}];
const result = data.reduce(
  (map, { products, ...rest }) =>
    map.concat(products.map(product => ({ ...rest, ...product }))),
  []
);

console.log(result);


Есть идеи?

10000