24

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!

4
  • Possible duplicate of Underscore to flatten nested array of parent/child objects This talks about underscore, but should work for lodash too. Commented Feb 20, 2017 at 22:56
  • That quite didn't work for me :/ Commented Feb 20, 2017 at 23:05
  • Please edit your question showing what you have tried and how it didn't work for you. Commented Feb 20, 2017 at 23:08
  • I also tried another method to _.merge the item.tags but it didn't work since it has the same keys. What am I missing here? Commented Feb 20, 2017 at 23:49

1 Answer 1

43

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>

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you @ryeballar! this is beautiful.
what if we want to retrieve only highest weight ones? Thanks in advance
@cilerler post that as another question.
@ryeballar never mind, figured out that as return _.maxBy(_.map(item.tags, tag => _.defaults({ name: item.name }, tag)),item.weight); thanks for the response.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.