test
test

Reputation: 18200

Traverse through object and insert elements

Let's say I have this:

const data = [
  {
    table: [
      [{
        textValue: 'One'
      },
      {
        textValue: 'Two',
        rows: 3
      },
      {
        textValue: 'Three',
        rows: 3
      },
      {
        textValue: 'Four'
      }],
      [{
        textValue: 'RED',
        rows: 2
      },
      {
        textValue: 'GREEN'
      },
      {
        textValue: 'BLUE',
        rows: 1
      }]
    ]
  }
];

What I am going after is where it traverses through the object (Object.entries() would work?) and see that rows exists and inserts X number of empty '' strings, so you'd have something like:

const data = [
  {
    table: [
      [{
        textValue: 'One'
      },
      {
        textValue: 'Two',
        rows: 3
      },
        '',
        '',
        '',
      {
        textValue: 'Three',
        rows: 3
      },
        '',
        '',
        '',
      {
        textValue: 'Four'
      }],
      [{
        textValue: 'RED',
        rows: 2
      },
        '',
        '',
      {
        textValue: 'GREEN'
      },
      {
        textValue: 'BLUE',
        rows: 1
      },
      ''
      ]
    ]
  }
];

I thought about using a for in but then I won't know the parent object to edit it when it comes time to push the element.

Upvotes: 1

Views: 63

Answers (3)

vincent
vincent

Reputation: 2181

Here is a solution that uses object-scan and is a bit more flexible. Using vanilla javascript might be the better choice, but that depends on your requirements

// const objectScan = require('object-scan');

const data = [{ table: [[ { textValue: 'One' }, { textValue: 'Two', rows: 3 }, { textValue: 'Three', rows: 3 }, { textValue: 'Four' } ], [ { textValue: 'RED', rows: 2 }, { textValue: 'GREEN' }, { textValue: 'BLUE', rows: 1 } ]] }];

const modify = (obj) => objectScan(['[*].table[*][*].rows'], {
  rtn: 'count',
  filterFn: ({ gparent, gproperty, value }) => {
    gparent.splice(gproperty + 1, 0, ...Array(value).fill(''));
  }
})(obj);

console.log(modify(data)); // returns number of modifications
// => 4

console.log(data);
// => [ { table: [ [ { textValue: 'One' }, { textValue: 'Two', rows: 3 }, '', '', '', { textValue: 'Three', rows: 3 }, '', '', '', { textValue: 'Four' } ], [ { textValue: 'RED', rows: 2 }, '', '', { textValue: 'GREEN' }, { textValue: 'BLUE', rows: 1 }, '' ] ] } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer: I'm the author of object-scan

Upvotes: 0

Nick Parsons
Nick Parsons

Reputation: 50684

You can use .map() and .flatMap() which will return an array of your inserted string characters based on the number of rows for the given object, that will be flattened into the resulting array:

const data = [{ table: [ [{ textValue: 'One' }, { textValue: 'Two', rows: 3 }, { textValue: 'Three', rows: 3 }, { textValue: 'Four' } ], [{ textValue: 'RED', rows: 2 }, { textValue: 'GREEN' }, { textValue: 'BLUE', rows: 1 } ] ] }];

const result = data.map(obj => ({
  ...obj,
  table: obj.table.map(arr =>
    arr.flatMap((iobj) => [iobj, ...Array(iobj.rows || 0).fill('')])
  )
}));

console.log(result);
.as-console-wrapper { max-height: 100% !important;} /* ignore */

Upvotes: 3

Maciej Kwas
Maciej Kwas

Reputation: 6419

Instead of extending data object I would copy its content to a new table with proper reducer method to ease the process, shall be easy as:

const transformedTable = data[0].table.map(e => e.reduce((acc, val) => ([...acc, val, ...(new Array(val.rows || 0)).fill('')]), []));

const data = [
      {
        table: [
          [{
            textValue: 'One'
          },
          {
            textValue: 'Two',
            rows: 3
          },
          {
            textValue: 'Three',
            rows: 3
          },
          {
            textValue: 'Four'
          }],
          [{
            textValue: 'RED',
            rows: 2
          },
          {
            textValue: 'GREEN'
          },
          {
            textValue: 'BLUE',
            rows: 1
          }]
        ]
      }
    ];

const transformedTable = data[0].table.map(e => e.reduce((acc, val) => ([...acc, val, ...(new Array(val.rows || 0)).fill('')]), []));

document.querySelector('#result').innerText = JSON.stringify(transformedTable);
<pre id="result"></pre>

Upvotes: 1

Related Questions