Home > Net >  groupby object keys and return array of indexes with same keys
groupby object keys and return array of indexes with same keys

Time:09-02

I have an array of objects that looks like below

var FinalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"}];

I am trying to loop through the array and return an array of items group by the key "name" which will hold indexes of the items with same key.

expected result like below:

[
{bene: [0,2]},
{leg: [1,3]},
{hello: [4]}
]

I've put together the below but can't get it to work.

var obj = FinalArray.reduce(function(agg, item, index, f) {
  var name = item.name || ""
  var index = FinalArray.findIndex(item)
/*   var copy = [...item.jArray];
   */  if (!agg[name]) {
 
    agg[name] = []
  }
  agg[name].push(index)

  return agg;
}, {})

fairly new to using reduce and groupby. any help is appreciated. Thanks

CodePudding user response:

You can generate an object of the names with their indexes with a reduce on the original array, just pushing indexes into the array for each name.

If you then want an array of those values (I'm not sure this is a better structure), you can use Object.entries to get the key value pairs and map those into individual objects in an array

var FinalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"}];

var obj = FinalArray.reduce((acc, { name }, i) => {
  acc[name] = (acc[name] || []).concat([i])
  return acc
}, {})

console.log(obj)

objArray = Object.entries(obj).map(([k, v]) => ({ [k] : v }))
console.log(objArray)
.as-console-wrapper { max-height: 100% !important; top: 0; }

CodePudding user response:

You can achieve this by just using two JavaScript methods Array.forEach() along with Object.keys().

Live Demo :

// Input array
var FinalArray = [
  {"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
  {"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
  {"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
  {"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
  {"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"}
];

const resObj = {};
const output = [];

// creating a object with the required key: values.
FinalArray.forEach((obj, index) => {
  resObj[obj.name] ? resObj[obj.name].push(index) : resObj[obj.name] = [index];
});

// destructuring the object into an array of objects.
Object.keys(resObj).forEach(key => {
    output.push({
    [key]: resObj[key]
  })
});

// final output
console.log(output);

CodePudding user response:

The OP might try a combination of ...

  • a reduce based approach which straightforwardly creates and collects an index/map of name based groups where the group key resemble an iterated item's name key, and the group value is an array of same name-value item-indices.

  • and a mapping of the reduced object's entries.

const finalArray = [
  {"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
  {"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
  {"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
  {"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
  {"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
];

console.log(
  'index/map based result ...',
  finalArray
    .reduce((groups, { name }, idx) => {

      (groups[name] ??= []).push(idx);
      return groups;
      
    }, {})
);
console.log(
  "OP's expected result ...",
  Object
    .entries(
      finalArray
        .reduce((groups, { name }, idx) => {

          (groups[name] ??= []).push(idx);
          return groups;

        }, {})
    )
    .map(([key, value]) => ({ [ key ]: value }))
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

Another approach was to solely stick to reduce, where one then needs to implement a reducer function which achieves everything in a single run and does both ...

  • keeping track of the (to be) generated groups and the (to be) collected indices

  • and aggregating the final result of the reduce method's accumulator/collector object which gets passed as the method's 2nd parameter ... its initialValue.

const finalArray = [
  {"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
  {"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
  {"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
  {"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
  {"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
];

const { result } = finalArray
  .reduce(({ result = [], groups = {} }, { name }, idx) => {

    let group = groups[name];
    if (!group) {

      group = groups[name] = { [ name ]: [] };
      result.push(group);
    }
    group[name].push(idx)

    return { result, groups };

  }, { result: [] });

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

  • Related