How does one, from a list of objects, group and collect just specific values which are explicitly referred to, each by its key?

Viewed 146

I have a data structure like

const dd = [{
  keyone: "test",
  two: "you",
  three: 'op',
}, {
  keyone: "youuuu",
  two: "ttt",
  three: 'op',
}, {
  keyone: "operation",
  two: "test",
  three: 'op',
}];

And I am wanting to be able to pull out keyone and two into an object like the following

const obj = { keyone: ['test', 'youuuu', 'operation'], two: ['you', 'ttt', 'test']}

I've achieved this using two maps and combining them but I would like to use only one loop if possible.

EDIT:

I am currently using destructuring to extract values:

const mapOne = dd.map(({ keyone }) => keyone);
const mapTwo = dd.map(({ two }) => two);
const test = {
  keyone: mapOne,
  two: mapTwo,
};
7 Answers

You could take an array of keys and group the values together.

const
    data = [{ keyone: "test", two: "you", three: 'op' }, { keyone: "youuuu", two: "ttt", three: 'op' }, { keyone: "operation", two: "test", three: 'op' }],
    keys = ['keyone', 'two'],
    grouped = data.reduce((r, o) => {
        keys.forEach(k => (r[k] ??= []).push(o[k]));
        return r;
    }, {});

console.log(grouped);

A generically implemented, thus re-usable and configurable function, which does exactly what the OP did ask for, would be close to the next provided example code ...

function groupAndCollectSpecifcEntriesOnly(collector, item) {
  const { keyList, result } = collector;

  keyList.forEach(key => {
    if (item.hasOwnProperty(key)) {

      (result[key] ??= []).push(item[key])
    }
  });
  return collector;
}

const sampleData = [{
  keyone: "test",
  two: "you",
  three: 'op',
}, {
  keyone: "youuuu",
  two: "ttt",
  three: 'op',
}, {
  keyone: "operation",
  two: "test",
  three: 'op',
}];

console.log(
  sampleData.reduce(groupAndCollectSpecifcEntriesOnly, {

    keyList: ['keyone', 'two'],
    result: {},

  }).result
);
console.log(
  sampleData.reduce(groupAndCollectSpecifcEntriesOnly, {

    keyList: ['three', 'keyone'],
    result: {},

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

You can do something like this:

const dd = [
{
  keyone: "test",
  two: "you",
  three: 'op'
},
{
  keyone: "youuuu",
  two: "ttt",
  three: 'op'
},
{
  keyone: "operation",
  two: "test",
  three: 'op'
}];
const result = dd.reduce((prev, acc, arr ) => {
       if (acc['keyone']) { prev['keyone'].push(acc['keyone']) } 
       if (acc['two']) { prev['two'].push(acc['two']) }
       return prev;
}, {keyone: [], two: []});

console.log(result);

Here I use object destructuring to extract 'keyone' and 'two' from the object data and push them into an object of arrays, within the same map loop)
Don't forget to check for undefined. My code here assumes you don't want zeros or empty strings.

const data = 
  [{ keyone: "test", two: "you", three: 'op' }, 
  { keyone: "youuuu", two: "ttt", three: 'op' }, 
  { keyone: "operation", two: "test", three: 'op' }];

   // declare an object 'result' with two keys, 
   // each with an array as it's property:
const result = { keyone:[], two:[] }
   // each array el of data is an object:
   // which can be destructured with {}
data.map(({ keyone, two }) => {
   if ( keyone )
      result.keyone.push( keyone );
   if ( two )
      result.two.push( two )
})

console.log( result )

You can do it by one iteration on your array using reduce and on every iteration, iterating over your object by Object.keys and forEach:

const data = [ { keyone: "test", two: "you", three: 'op' }, { keyone: "youuuu", two: "ttt", three: 'op' }, { keyone: "operation", two: "test", three: 'op' }];
const targetKeys = ['keyone', 'two']

const result = data.reduce((acc, obj)=> {
  targetKeys.forEach(k => { (acc[k] = acc[k] || []).push(obj[k]) });
  return acc;
}, {});

console.log(result);

I'm fairly new to JavaScript and maybe my solution is not the best. I created a function, where you can add as an optional parameter the amount of keys you want to getter the information from. I asumed that you don't know the name of the keys.

const dd = [{
  keyone: "test",
  two: "you",
  three: 'op',
}, {
  keyone: "youuuu",
  two: "ttt",
  three: 'op',
}, {
  keyone: "operation",
  two: "test",
  three: 'op',
}];

getterInformation(dd);

function getterInformation(object, keyCount = Object.keys(object).length) {
  let objectWithDesiredKey = {};

  for (let index = 0; index < keyCount; index++) {
    objectWithDesiredKey[`${Object.keys(object[0])[index]}`] = [];
  }

  object.forEach((items) => {
    for (const key in items) {
      if (key in objectWithDesiredKey) {
        objectWithDesiredKey[key].push(items[key]);
      }
    }
  });

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

const dd = [{
        keyone: "test",
        two: "you",
        three: 'op'
    },
    {
        keyone: "youuuu",
        two: "ttt",
        three: 'op'
    },
    {
        keyone: "operation",
        two: "test",
        three: 'op'
    }
];

const pullOut = (...keys) => {
    return keys.map(key => {
        const val = dd.reduce((pV, cV, cI) => {
            pV.push(cV[key]);
            return pV;
        }, []);
        return {
            [key]: val
        };
    }).reduce(((r, c) => Object.assign(r, c)), {});
};

console.log(pullOut('keyone', 'two'));

Related