Home > Net >  How to reduce an array of objects to the required format?
How to reduce an array of objects to the required format?

Time:04-30

I have a problem with proper grouping of objects in an array.

I have an array in this format:

const places = [
  {
    id: 1,
    name: "p 1",
    icon: "icon-p",
    parent_id: null,
  },
  {
    id: 2,
    name: "p 2",
    icon: "icon-p",
    parent_id: 1,
  },
  {
    id: 3,
    name: "p 3",
    icon: "icon-p",
    parent_id: 1,
  },
  {
    id: 4,
    name: "t 1",
    icon: "icon-t",
    parent_id: null,
  },
  {
    id: 5,
    name: "t 2",
    icon: "icon-t",
    parent_id: 4,
  },
  {
    id: 6,
    name: "t 3",
    icon: "icon-t",
    parent_id: 4,
  },
  {
    id: 7,
    name: "a 1",
    icon: "icon-a",
    parent_id: null,
  },
  {
    id: 8,
    name: "b 1",
    icon: "icon-b",
    parent_id: null,
  },
  {
    id: 9,
    name: "h 1",
    icon: "icon-h",
    parent_id: null,
  },
  {
    id: 11,
    name: "h 2",
    icon: "icon-h",
    parent_id: 9,
  },
  {
    id: 12,
    name: "h 3",
    icon: "icon-h",
    parent_id: 9,
  },
  {
    id: 13,
    name: "h 4",
    icon: "icon-h",
    parent_id: 9,
  },
];


const groupReultsByIcon = places.reduce((r, { icon, ...object }) => {
  let temp = r.find((o) => o.icon === icon);
  if (!temp) r.push((temp = { icon, children: [] }));
  temp.children.push(object);
  return r;
}, []);


groupReultsByIcon.forEach(({ icon, children }) => {
  console.log('icon-name: ', icon);
  console.log('children-array: ', children);
});

The code that I have managed to prepare so far is, unfortunately, only grouping by icon.

I am trying to get such an array:

const newArrayObject = [
  {
    id: 1,
    icon: "icon-p",
    children: [
      {
        id: 1,
        name: "p 1",
        icon: "icon-p",
        parent_id: null,
      },
      {
        id: 2,
        name: "p 2",
        icon: "icon-p",
        parent_id: 1,
      },
      {
        id: 3,
        name: "p 3",
        icon: "icon-p",
        parent_id: 1,
      },
    ],
  },
  {
    id: 4,
    icon: "icon-t",
    children: [
      {
        id: 4,
        name: "t 1",
        icon: "icon-t",
        parent_id: null,
      },
      {
        id: 5,
        name: "t 2",
        icon: "icon-t",
        parent_id: 4,
      },
      {
        id: 6,
        name: "t 3",
        icon: "icon-t",
        parent_id: 4,
      },
    ],
  },
  {
    id: 7,
    icon: "icon-a",
    children: [
      {
        id: 7,
        name: "a 1",
        icon: "icon-a",
        parent_id: null,
      },
    ],
  },
  {
    id: 8,
    icon: "icon-b",
    children: [
      {
        id: 8,
        name: "b 1",
        icon: "icon-b",
        parent_id: null,
      },
    ],
  },
  {
    id: 9,
    icon: "icon-h",
    children: [
      {
        id: 9,
        name: "h 1",
        icon: "icon-h",
        parent_id: null,
      },
      {
        id: 11,
        name: "h 2",
        icon: "icon-h",
        parent_id: 9,
      },
      {
        id: 12,
        name: "h 3",
        icon: "icon-h",
        parent_id: 9,
      },
      {
        id: 13,
        name: "h 4",
        icon: "icon-h",
        parent_id: 9,
      },
    ],
  },
];

As you can see grouping should follow parent_id and id An object that parent_id === null should have children and in it itself as well as objects with its id.

CodePudding user response:

Using Array.reduce(), it can be done as follows:

const places = [
  {
    id: 1,
    name: "p 1",
    icon: "icon-p",
    parent_id: null,
  },
  {
    id: 2,
    name: "p 2",
    icon: "icon-p",
    parent_id: 1,
  },
  {
    id: 3,
    name: "p 3",
    icon: "icon-p",
    parent_id: 1,
  },
  {
    id: 4,
    name: "t 1",
    icon: "icon-t",
    parent_id: null,
  },
  {
    id: 5,
    name: "t 2",
    icon: "icon-t",
    parent_id: 4,
  },
  {
    id: 6,
    name: "t 3",
    icon: "icon-t",
    parent_id: 4,
  },
  {
    id: 7,
    name: "a 1",
    icon: "icon-a",
    parent_id: null,
  },
  {
    id: 8,
    name: "b 1",
    icon: "icon-b",
    parent_id: null,
  },
  {
    id: 9,
    name: "h 1",
    icon: "icon-h",
    parent_id: null,
  },
  {
    id: 11,
    name: "h 2",
    icon: "icon-h",
    parent_id: 9,
  },
  {
    id: 12,
    name: "h 3",
    icon: "icon-h",
    parent_id: 9,
  },
  {
    id: 13,
    name: "h 4",
    icon: "icon-h",
    parent_id: 9,
  },
];

const result = places.reduce((prev, curr) =>  {
  const parent = prev.find(p => p.id === curr.parent_id);
  if (parent) {
    if (!parent.children) {      
      parent.children = [];
    }
    parent.children.push(curr);
  } else {
    prev.push(curr);
  }  
  return prev;
}, []);

console.log(result);

CodePudding user response:

You can check for children in one level and then add to it. This will check only for one nested level. You can make it recursive if you want.

Try like below

const places = [ { id: 1, name: "p 1", icon: "icon-p", parent_id: null, }, { id: 2, name: "p 2", icon: "icon-p", parent_id: 1, }, { id: 3, name: "p 3", icon: "icon-p", parent_id: 1, }, { id: 4, name: "t 1", icon: "icon-t", parent_id: null, }, { id: 5, name: "t 2", icon: "icon-t", parent_id: 4, }, { id: 6, name: "t 3", icon: "icon-t", parent_id: 4, }, { id: 7, name: "a 1", icon: "icon-a", parent_id: null, }, { id: 8, name: "b 1", icon: "icon-b", parent_id: null, }, { id: 9, name: "h 1", icon: "icon-h", parent_id: null, }, { id: 11, name: "h 2", icon: "icon-h", parent_id: 9, }, { id: 12, name: "h 3", icon: "icon-h", parent_id: 9, }, { id: 13, name: "h 4", icon: "icon-h", parent_id: 9, }, ];

const output = places.reduce((prev, curr) => {
  if (curr.parent_id === null) {
    prev.push(curr);
  } else {
    const parent = prev.find(({ id }) => id === curr.parent_id);
    if (parent) {
      parent.children
        ? parent.children.push(curr)
        : (parent.children = [{ ...parent }, curr]);
    }
  }
  return prev;
}, []);

console.log(JSON.stringify(output, null, 2));

CodePudding user response:

You can easily achieve the result using Map as:

const places = [
  {
    id: 1,
    name: 'p 1',
    icon: 'icon-p',
    parent_id: null,
  },
  {
    id: 2,
    name: 'p 2',
    icon: 'icon-p',
    parent_id: 1,
  },
  {
    id: 3,
    name: 'p 3',
    icon: 'icon-p',
    parent_id: 1,
  },
  {
    id: 4,
    name: 't 1',
    icon: 'icon-t',
    parent_id: null,
  },
  {
    id: 5,
    name: 't 2',
    icon: 'icon-t',
    parent_id: 4,
  },
  {
    id: 6,
    name: 't 3',
    icon: 'icon-t',
    parent_id: 4,
  },
  {
    id: 7,
    name: 'a 1',
    icon: 'icon-a',
    parent_id: null,
  },
  {
    id: 8,
    name: 'b 1',
    icon: 'icon-b',
    parent_id: null,
  },
  {
    id: 9,
    name: 'h 1',
    icon: 'icon-h',
    parent_id: null,
  },
  {
    id: 11,
    name: 'h 2',
    icon: 'icon-h',
    parent_id: 9,
  },
  {
    id: 12,
    name: 'h 3',
    icon: 'icon-h',
    parent_id: 9,
  },
  {
    id: 13,
    name: 'h 4',
    icon: 'icon-h',
    parent_id: 9,
  },
];

const mapObj = places.reduce((acc, curr) => {
  const { id, name, icon, parent_id } = curr;
  if (!acc.get(parent_id)) {
    acc.set(id, {
      id,
      icon,
      children: [curr],
    });
  } else acc.get(parent_id)?.children?.push(curr);
  return acc;
}, new Map());

const result = [...mapObj.values()];
console.log(result);

  • Related