简体   繁体   中英

Simple way to turn array of objects into object with grouped keys as arrays

I am looking for a simple way to do the following. I have tried to do this with lodash.reduce and it is clunky, is there an easier way.

From:

[{a: 'meow'}, {a: 'woof'}]

To:

{a: ['meow', 'woof']}

You can do that with pure JS, no need of loadash.

Call the reduce method of arrays on your input array, and reduce the array to an object, looping over the keys of your inner objs:

 const input = [{a: 'meow'}, {a: 'woof'}, {b: 'hi'}, {a: 'dog', c: 'bye'}, {}]; console.log(input.reduce((acc, val) => { Object.keys(val).forEach(key => { if(!acc[key]) { acc[key] = []; } acc[key].push(val[key]); }); return acc; }, {}));

You can use lodash#assignWith to assign all properties their respective values into one object, together with a customizer function to determine how you want to structure the object.

const result = _.assignWith({}, ...data, (v = [], s) => v.concat(s));

Note: To make sure that we don't mutate any of the objects in the data array, I passed an empty object as the first parameter to act as the destination object.

 const data = [ { a: 'meow' }, { a: 'woof', k: 'hey' }, { k: 'yo', d: 'hehe' }, { d: 'wazup', q: 'ohoho' } ]; const result = _.assignWith({}, ...data, (v = [], s) => v.concat(s)); console.log(result);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

I had some issues with typescript and lodash.reduce, this worked.

export function getFuncsObject(funcs): Record<Funcs, Case[]> {
  let f = { ...funcs };
  f = lodash.mapValues(f, () => []);
  return f;
}

export function mockMerge(funcs, mocks: Record<Funcs, Case | null>[]): Record<Funcs, Case[]> {
  const f = getFuncsObject(funcs);
  lodash.each(mocks, (v, k) => {
    f[k].push(v);
  });
  return f;
}

One option would be to use two reductions as follows:

 const input = [{ a: 'meow' }, { a: 'woof' }, { b: 'moo' }]; const result = input .reduce((itemResult, item) => Object.keys(item) .reduce((keyResult, key) => ({ ...keyResult, [key]: (keyResult[key] || []).concat(item[key]) }), itemResult), {}); console.log(result)

Not sure if this is clunky compared to your current solution, but it's fairly concise and does not require an external library.

Without using any external libraries or reduce.

 const input = [ {a: 'meow'}, {a: 'woof'}, {b: 'hi'}, {a: 'dog', c: 'bye'}, {} ]; let output = {}; input.forEach((inputObj) => { for(let key in inputObj){ if(!output[ key ]){ output[ key ] = []; } output[ key ].push(inputObj[key]) } }); console.log(output);

I am looking for a simple way to do the following. I have tried to do this with lodash.reduce and it is clunky, is there an easier way.

From:

[{a: 'meow'}, {a: 'woof'}]

To:

{a: ['meow', 'woof']}

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