5

I have this array of objects, that I need to modify to make it easier the rendering.

const items = [
  {
    tab: 'Results',
    section: '2017',
    title: 'Full year Results',
    description: 'Something here',
  },
    {
    tab: 'Results',
    section: '2017',
    title: 'Half year Results',
    description: 'Something here',
  },
    {
    tab: 'Reports',
    section: 'Marketing',
    title: 'First Report',
    description: 'Something here',
  },
  ...
];

and I'm trying to modify it, grouping them by specific keys. The idea is to have this output. As you can see the names of the keys could be different than the actual names in the items. I think that makes a bit different from previous posts.

const output = [
  {
    tab: 'Results',
    sections: [
      {
         section: '2017',
         items: [ { 'item that belongs here' }, { ... } ],
      },
  },
  {
    tab: 'Reports',
    sections: [
      {
         section: 'Marketing',
         items: [ { ... }, { ... } ],
      },
  },
...
]

I tried using lodash.groupby, but it doesn't do exactly what i'm looking for. Any idea about how to approach it?

Many thanks!!

2

2 Answers 2

4

This can be done with a clever combinartion of _.map and _.groupBy.

const items = [
  {
    tab: 'Results',
    section: '2017',
    title: 'Full year Results',
    description: 'Something here',
  },
    {
    tab: 'Results',
    section: '2017',
    title: 'Half year Results',
    description: 'Something here',
  },
    {
    tab: 'Reports',
    section: 'Marketing',
    title: 'First Report',
    description: 'Something here',
  }
];

function groupAndMap(items, itemKey, childKey, predic){
    return _.map(_.groupBy(items,itemKey), (obj,key) => ({
        [itemKey]: key,
        [childKey]: (predic && predic(obj)) || obj
    }));
}

var result = groupAndMap(items,"tab","sections", 
                   arr => groupAndMap(arr,"section", "items"));


console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

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

Comments

3

You could use an object without additional libraries.

The object contains a property _ which keeps the nested arrays of the given nested group.

var items = [{ tab: 'Results', section: '2017', title: 'Full year Results', description: 'Something here' }, { tab: 'Results', section: '2017', title: 'Half year Results', description: 'Something here' }, { tab: 'Reports', section: 'Marketing', title: 'First Report', description: 'Something here' }],
    keys = { tab: 'sections', section: 'items' }, // or more if required
    result = [],
    temp = { _: result };

items.forEach(function (object) {
    Object.keys(keys).reduce(function (level, key) {
        if (!level[object[key]]) {
            level[object[key]] = { _: [] };
            level._.push({ [key]: object[key], [keys[key]]: level[object[key]]._ });
        }
        return level[object[key]];
    }, temp)._.push({ title: object.title, description: object.description });
});

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

8 Comments

The solution looks really neat, thanks! Also @Jamiec solution works perfect, now the only doubt would be which one is more efficient...
@JCGarcia I would bet on this one, more native than using lodash. @Nina, is a Map better than using a simple object {}? Very nice solution btw!!
@sjahan, the object is maybe faster with a for loop.
I would personally always defer to Nina's better knowledge ;) Except that this doesnt do the second level of aggregation on sections
@Jamiec, sorry, haven't seen the nested grouping.
|

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.