简体   繁体   中英

Normalize/Flatten a JS array using LoDash or similar?

I need to be able to normalize a javascript object or flatten it, I was hoping to be able to do something with lodash but I am at a loss. I tried writing my own converter but it seemed way over complicated and I though that lodash would be able to do something like this.

I am placing the Original Array I have, it has 3 items with sub arrays. (see below)

This is what I expect (creating my new object), so everything is flattened and added to the 'name' (see testProduct1 and testProduct2 below), if no colors, locations are available then the name is just the original name (see testProduct3 below).

{
   name: ‘testProduct1 RED NewYork’
},
{
   name: ‘testProduct1 RED London’
},
{
   name: ‘testProduct1 YELLOW NewYork’
},
{
   name: ‘testProduct1 YELLOW London’
},
{
   name: ‘testProduct2 WHITE NewYork’
},
{
   name: ‘testProduct2 WHITE London’
},
{
   name: ‘testProduct3’
}

Here is the example of the ORIGINAL array

{
    name: ‘testProduct1’,
    colors: [
       ‘RED’,
       ‘YELLOW’
    ],
    locations: [
       ‘New York’,
       ‘London’
    ]
},
{
    name: ‘testProduct2’,
    colors: [
       ‘WHITE’
    ],
    locations: [
       ‘New York’,
       ‘London’
    ]
},
{
    name: ‘testProduct3’,
}

This is a solution in plain Javascript.

 var data = [{ name: 'testProduct1', colors: ['RED', 'YELLOW'], locations: ['New York', 'London'] }, { name: 'testProduct2', colors: ['WHITE'], locations: ['New York', 'London'] }, { name: 'testProduct3', }], flat = function (array) { var order = ['colors', 'locations'], r = []; array.forEach(function (a) { function getParts(parts) { if (parts.length >= order.length) { parts.unshift(a.name); r.push({ name: parts.filter(Boolean).join(' ') }); return; } (a[order[parts.length]] || ['']).forEach(function (b) { getParts(parts.concat(b)); }); } getParts([]); }); return r; }(data); document.write('<pre>' + JSON.stringify(flat, 0, 4) + '</pre>'); 

I guess you want a map

list.map((element) => {
    return {
        name: [element.name].concat(element.colors, element.locations).join(' ')
    };
});
var resultArr = inArr.reduce((initArr, cur) =>
  {
    if (cur.colors && cur.locations)
    {
      cur.colors.forEach(col => 
      cur.locations.forEach(loc =>
        initArr.push({ name: cur.name + ' ' + col + ' ' + loc })));
    }  
    else
    {
      initArr.push({ name: cur.name });
    }

    return initArr;
  }, [] /* Passed as initArr */);

OR

Even more concise

var resultArr = inArr.reduce((initArr, cur) =>
  {
    for (let col of cur.colors || ['']) 
      for (let loc of cur.locations || [''])
        initArr.push({ name: (cur.name + ' ' + col + ' ' + loc).trim() });
    return initArr;
  }, [] /* Passed as initArr */);

It might be easier to write a set of basic loops:

var result = [];
for (let i = 0; i < arr.length; i++) {
  let colors = arr[i].colors || [];
  for (let j = 0; j < colors.length; j++) {
    let locations = arr[i].locations || [];
    for (let k = 0; k < locations.length; k++) {
      result.push({name: arr[i].name + ' ' + colors[j] + ' ' + locations[k]]});
    ]
  }
}

If you really want to write this in functional style, then one idea is:

[].concat(...arr.map(
  elt => (elt.colors || []).map(
    color => (elt.locations || []).map(
      location => ({name: elt.name + ' ' + color + ' ' + location})))))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM