Search code examples
lodash

Flatten an nested array of objects using Lodash


My object looks like this:

const features = [{
                  'name': 'feature1', 'tags':
                  [{'weight':10, 'tagName': 't1'},{'weight':20, 'tagName': 't2'}, {'weight':30, 'tagName': 't3'}]
                  },
                  {
                  'name': 'feature2', 'tags':
                  [{'weight':40, 'tagName': 't1'}, {'weight':5, 'tagName':'t2'}, {'weight':70, 'tagName':'t3'}]
                  },
                  {
                  'name': 'feature3', 'tags':[
                  {'weight':50, 'tagName': 't1'}, {'weight':2, 'tagName': 't2'}, {'weight':80, 'tagName': 't3'}]
                 }]

I would like my output to look something like this:

const features = [{'name':'feature1', 'weight':10, 'tagName':'t1'}, 
                  {'name':'feature1', 'weight':20, 'tagName':'t2'}, ...
                  {'name':'feature3', 'weight':80, 'tagName':'t3'}]

I tried to merge and the flatten but it does not work.

Update 1 I tried this:

let feat = features;

results = []

_.each(feat, (item) => { 
                        console.log(item);
                        results.push(_.flatten(_.pick(item.tags, 'weight'))); // pick for certain keys. 
                       }

Update 2 This solved my problem

_.each(features, (item) => { 
  _.each(item.tags, (itemTag) => { 
    results.push({'name':item.name, 'weight':itemTag.weight, 'tagName':itemTag.tagName})})})

But I want to know if there is a more lodash way to do this!


Solution

  • The approach below uses flatMap to flatten tags acquired through map. Finally, use the spread operator to assign the values from tag and the feature's name.

    const result = _.flatMap(features, ({ name, tags }) =>
      _.map(tags, tag => ({ name, ...tag }))
    );
    

    const features = [{
        'name': 'feature1',
        'tags': [{
          'weight': 10,
          'tagName': 't1'
        }, {
          'weight': 20,
          'tagName': 't2'
        }, {
          'weight': 30,
          'tagName': 't3'
        }]
      },
      {
        'name': 'feature2',
        'tags': [{
          'weight': 40,
          'tagName': 't1'
        }, {
          'weight': 5,
          'tagName': 't2'
        }, {
          'weight': 70,
          'tagName': 't3'
        }]
      },
      {
        'name': 'feature3',
        'tags': [{
          'weight': 50,
          'tagName': 't1'
        }, {
          'weight': 2,
          'tagName': 't2'
        }, {
          'weight': 80,
          'tagName': 't3'
        }]
      }
    ];
    
    const result = _.flatMap(features, ({ name, tags }) =>
      _.map(tags, tag => ({ name, ...tag }))
    );
    
    console.log(result);
    .as-console-wrapper{min-height:100%;top:0}
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

    Here's a plain javascript solution that uses Array#reduce and Array#map with the help of Array#concat to flatten the array.

    const result = features.reduce(
      (result, { name, tags }) => result
        .concat(tags.map(tag => ({ name, ...tag }))), 
      []
    );
    

    const features = [{
        'name': 'feature1',
        'tags': [{
          'weight': 10,
          'tagName': 't1'
        }, {
          'weight': 20,
          'tagName': 't2'
        }, {
          'weight': 30,
          'tagName': 't3'
        }]
      },
      {
        'name': 'feature2',
        'tags': [{
          'weight': 40,
          'tagName': 't1'
        }, {
          'weight': 5,
          'tagName': 't2'
        }, {
          'weight': 70,
          'tagName': 't3'
        }]
      },
      {
        'name': 'feature3',
        'tags': [{
          'weight': 50,
          'tagName': 't1'
        }, {
          'weight': 2,
          'tagName': 't2'
        }, {
          'weight': 80,
          'tagName': 't3'
        }]
      }
    ];
    
    const result = features.reduce(
      (result, { name, tags }) => result
        .concat(tags.map(tag => ({ name, ...tag }))), 
      []
    );
    
    console.log(result);
    .as-console-wrapper{min-height:100%;top:0}
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>