2

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']}
1
  • Care to share the effort? A user with your rep should know the importance of it Commented Jan 3, 2019 at 7:33

5 Answers 5

2

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;
}, {}));

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

1 Comment

I have added more objects to the input set, just to show this works over a generalized set. +1. You can rollback if you dislike this change. I apologize in that case
2

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>

2 Comments

also, _.mergeWith can be used for the same
Since the OP's situation doesn't deal with recursively assigning values, then I simply opted to use lodash#assignWith
0

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;
}

Comments

0

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.

Comments

0

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);

Comments

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.