-2

Given an array of objects with some common properties like foosWithBar, how can I create another array of objects grouped by those common properties like barsWithFoos without using libraries like lodash? I've found examples that create an object grouped by key using reduce(), but that is not quite what I want.

const foosWithBar = [
  {
    id: 'Foo A',
    bar: {
      id: 'Bar 1',
    },
  },
  {
    id: 'Foo B',
    bar: {
      id: 'Bar 1',
    },
  },
  {
    id: 'Foo C',
    bar: {
      id: 'Bar 2',
    },
  },
  {
    id: 'Foo D',
    bar: {
      id: 'Bar 2',
    },
  },
]

const barsWithFoos = [
  {
    id: 'Bar 1',
    foos: [
      {
        id: 'Foo A',
      },
      {
        id: 'Foo B',
      },
    ],
  },
  {
    id: 'Bar 2',
    foos: [
      {
        id: 'Foo C',
      },
      {
        id: 'Foo D',
      },
    ],
  },
]
Rick
  • 49
  • 7
  • _"create an object grouped by key ... but that is not quite what I want."_ - Why is this not what you want? The _"key"_ in this case is the value in `bar.id`. – Andreas Aug 17 '21 at 16:23
  • And this has nothing to do with `json` – Andreas Aug 17 '21 at 16:23
  • Are you saying transform `foosWithBar` into `barsWithFoos`? What have you tried so far? You're expected to at least try and we can help if you have issues – StudioTime Aug 17 '21 at 16:24

2 Answers2

1

Iterate each foo item and search it in the barsWithFoos array. If it isn't there, you will need to include it with barsWithFoos.push({ id: foo.bar.id, foos: [] }). Then just push the foo in the bar list with barsWithFoos[i - 1].foos.push({ id: foo.id }):

const foosWithBar = [  {id: 'Foo A',bar: { id: 'Bar 1', }, }, {    id: 'Foo B',    bar: {      id: 'Bar 1',    },  },  {    id: 'Foo C',   bar: {      id: 'Bar 2',    },  },  {   id: 'Foo D',   bar: {      id: 'Bar 2',    },  },];

const barsWithFoos = [];
foosWithBar.forEach(foo => {
  const i = barsWithFoos.findIndex(bar => bar.id === foo.bar.id) + 1 
            || barsWithFoos.push({ id:  foo.bar.id, foos: [] });
  barsWithFoos[i - 1].foos.push({ id: foo.id });
})

console.log(barsWithFoos);
AlexSp3
  • 2,201
  • 2
  • 7
  • 24
1

Use reduce to move it into a new format. Using an object to keep track of the "bars" that you already referenced. You than use Object.values, to get your array.

const foosWithBar = [
  { id: 'Foo A', bar: { id: 'Bar 1', }, },
  { id: 'Foo B', bar: { id: 'Bar 1', }, },
  { id: 'Foo C', bar: { id: 'Bar 2', }, },
  { id: 'Foo D', bar: { id: 'Bar 2', }, },
];

const opposite = Object.values(
  foosWithBar.reduce(
    function(acc, item) {
      if (!acc[item.bar.id]) { // have we seen it yet?
        acc[item.bar.id] = { // if not create the object
          id: item.bar.id,
          foos: [{
            id: item.id
          }]
        };
      } else { // if we seen it, just add the new foo
        acc[item.bar.id].foos.push({
            id: item.id
        });
      }
      return acc;
    }, {})
);
console.log(opposite);
epascarello
  • 204,599
  • 20
  • 195
  • 236