简体   繁体   中英

Underscore/Lodash: Group object by substring of key

I am attempting to Group a object into a more organised structure based on a substring of the object key.

Below is a example of the object that I am passing:

var data = {
  "summ_example_1": {
    "value": 40464.284237
  },
  "summ_example_number_2": {
    "value": 39260.605837
  },
  "in_process_example_1": {
    "count": 10,
    "value": 10
  },
  "in_process_example_2": {
    "count": 12,
    "value": 12.5
  },
  "in_process_example_3": {
    "count": 0,
    "value": 0
  },
  "awaiting_example_1": {
    "count": 17,
  },
  "awaiting_example_2": {
    "count": 51,
  }
}

The output that I am wanting is:

{ summ:
    ["summ_example_1": {"value": 40464.284237},
     "summ_example_number_2": {"value": 39260.605837}],
  in:
    ["in_process_example_1": {"count": 10, "value": 10},
     "in_process_example_2": {"count": 12, "value": 12.5},
     "in_process_example_3": {"count": 0, "value": 0}],
  awaiting:
    ["awaiting_example_1": {"count": 17},
     "awaiting_example_2": {"count": 51"}]}

I have attempted grouping the object using groupBy within both Lodash and Underscore.js without any luck.

Inside underscore I can use the following code (Note that this does not work in Lodash as I can not seem to get the value of the Object Key:

var grouped = _.groupBy(data, function(val, key){
    return key.substr(0, key.indexOf('_'));
});

which produces the following output:

{ summ:
    [{"value": 40464.284237},
     {"value": 39260.605837}],
  in:
    [{"count": 10, "value": 10},
     {"count": 12, "value": 12.5},
     {"count": 0, "value": 0}],
  awaiting:
    [{"count": 17},
     {"count": 51"}]}

However I want to keep the Object Keys inside my output and as you can see it is removing them.

Is what I am doing possible?

Apologies if this doesn't make sense or has already been asked, but I have been searching for a solution for more time than I would have liked and am starting to run out of ideas.

Thank you for taking the time to read this and please feel free to ask any questions!

You could take the entries of the object and build a new key and group by this key.

 var data = { summ_example_1: { value: 40464.284237 }, summ_example_number_2: { value: 39260.605837 }, in_process_example_1: { count: 10, value: 10 }, in_process_example_2: { count: 12, value: 12.5 }, in_process_example_3: { count: 0, value: 0 }, awaiting_example_1: { count: 17 }, awaiting_example_2: { count: 51 } }, result = Object.entries(data).reduce((r, [k, v]) => { var key = k.replace(/_.*$/, '') ; (r[key] = r[key] || {})[k] = v; return r; }, {}); console.log(result); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

Lodash's _.groupBy() calls the iteratee with the only the value, in addition the result of groupBy is an object of arrays, not an object of objects like you need.

Solution 1 - lodash:

You can create a function with _.flow() that maps each object to include the group key ( summ for example), and them merge them together:

 const { flow, map, partialRight: pr, spread, merge } = _ const fn = flow( pr(map, (v, k) => ({ [k.split('_')[0]]: { [k]: v }})), // format each object to have the group key - summ for example spread(merge) // merge all objects together ) const data = { summ_example_1: { value: 40464.284237 }, summ_example_number_2: { value: 39260.605837 }, in_process_example_1: { count: 10, value: 10 }, in_process_example_2: { count: 12, value: 12.5 }, in_process_example_3: { count: 0, value: 0 }, awaiting_example_1: { count: 17 }, awaiting_example_2: { count: 51 } }; const result = fn(data); console.log(result); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script> 

Solution 2 - lodash/fp

Since lodash/fp _.map() doesn't pass the key to the iteratee, use _.pairs() to create a [key, value] tuple. Map the tuples to include the group key, and merge them all together.

 const { flow, toPairs, map, mergeAll } = _ const fn = flow( toPairs, map(([k, v]) => ({ [k.split('_')[0]]: { [k]: v }})), mergeAll ) const data = { summ_example_1: { value: 40464.284237 }, summ_example_number_2: { value: 39260.605837 }, in_process_example_1: { count: 10, value: 10 }, in_process_example_2: { count: 12, value: 12.5 }, in_process_example_3: { count: 0, value: 0 }, awaiting_example_1: { count: 17 }, awaiting_example_2: { count: 51 } }; const result = fn(data); console.log(result); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 
 <script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script> 

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