0

I have a single array of objects and I would like to reduce it down to another array of objects based on two keys value pairs.

const original =
    [
        {
            key1: 'a',
            key2: 'AA',
            value: 1
        },
        {
            key1: 'a',
            key2: 'AA',
            anotherValue: 2
        },
        {
            key1: 'b',
            key2: 'BB',
            value: 1
        },
        {
            key1: 'a',
            key2: 'AA',
            yetAnother: 3
        },
        {
            key1: 'b',
            key2: 'BB',
            anotherValue: 4
        },
        {
            key1: 'c',
            key2: 'CC',
            value: 1
        }
    ];

Should be transformed into:

const result =
    [
        {
            key1: 'a',
            key2: 'AA',
            value: 1,
            anotherValue: 2,
            yetAnother: 3
        },
        {
            key1: 'b',
            key2: 'BB',
            value: 1,
            anotherValue: 4
        },
        {
            key1: 'c',
            key2: 'CC',
            value: 1
        },
    ];

Tired using map and reduce and even lodash. However, all my attempts were futile.

3
  • 1
    Your attempts would be far less futile if you included them in your question Commented Oct 15, 2020 at 3:55
  • They were not even close. I'm relatively new to JS Commented Oct 15, 2020 at 3:58
  • How do you know you weren't close. The best idea when using StackOverflow is to include your attempts. Who knows, you might be very close or just have a typo and getting somebody else to check over your code can quickly pinpoint problems. You might even solve it yourself while trying to write out what you tried 🦆 Commented Oct 15, 2020 at 4:01

2 Answers 2

2

Using Array.reduce, you can group the objects by key1 and key2 value pairs. And the variable groupBy object values contain the result you want and you can generate the values only using Object.values(groupBy).

const original = [
  { key1: 'a', key2: 'AA', value: 1 },
  { key1: 'a', key2: 'AA', anotherValue: 2 },
  { key1: 'b', key2: 'BB', value: 1 },
  { key1: 'a', key2: 'AA', yetAnother: 3 },
  { key1: 'b', key2: 'BB', anotherValue: 4 },
  { key1: 'c', key2: 'CC', value: 1 }
];

const groupBy = original.reduce((acc, cur) => {
  const { key1, key2, ...rest } = cur;
  const key = key1 + "_" + key2;
  acc[key] ? acc[key] = { ...acc[key], ...rest } : acc[key] = cur;
  return acc;
}, {});

const result = Object.values(groupBy);
console.log(result);

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

Comments

0

Using Array.prototype.reduce(), build up a Map of entries, keyed by the combination of any key* properties while merging in the other properties.

Then you can convert the Map values into a new array

const original = [{"key1":"a","key2":"AA","value":1},{"key1":"a","key2":"AA","anotherValue":2},{"key1":"b","key2":"BB","value":1},{"key1":"a","key2":"AA","yetAnother":3},{"key1":"b","key2":"BB","anotherValue":4},{"key1":"c","key2":"CC","value":1}]

const t1 = performance.now()

const result = [...original.reduce((map, obj) => {
  // create a key from all the "key*" properties
  const key = Object.keys(obj)
    .filter(key => key.startsWith("key"))
    .sort()
    .map(key => obj[key]).join(":") // looks like "a:AA", "b:BB", etc
    
  // merge with previously found matches
  const entry = {
    ...(map.get(key) ?? {}),
    ...obj
  }
  
  // collect the merged object
  return map.set(key, entry)
}, new Map()).values()]

const t2 = performance.now()
console.info(result, `in ${t2 - t1}ms`)
.as-console-wrapper { max-height: 100% !important; }

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.