Use reduce() method to reorder object array!

Asked

Viewed 74 times

1

Personal have the following array of objects:

  old: [
    {
      id: 1,
      date: '2020-08-27T00:00:00',
      title: 'Title 1',
    },
    {
      id: 2,
      date: '2020-08-27T00:00:00',
      title: 'Title 2',
    },
    {
      id: 3,
      date: '2020-08-25T00:00:00',
      title: 'Title 3',
    }
  ],

I need him to stay reordered where the field date is the same. Example:

  items: [
    {
      date: '2020-08-27T00:00:00',
      childrens: [
        {
          id: 1,
          title: 'Title 1',
        },
        {
          id: 2,
          title: 'Title 2',
        }
      ]
    },
    {
      date: '2020-08-27T00:00:00',
      childrens: [
        {
          id: 3,
          title: 'Title 3',
        }
      ]
    }
  ]

I thought about using the method reduce() for this, but I think I’m not doing it right.. but ta almost la.. follows my code:

const old = [
  {
    id: 1,
    date: '2020-08-27T00:00:00',
    title: 'Title 1',
  },
  {
    id: 2,
    date: '2020-08-27T00:00:00',
    title: 'Title 2',
  },
  {
    id: 3,
    date: '2020-08-25T00:00:00',
    title: 'Title 3',
  }
];

const items = old.reduce((acc, item) => {
  if (!acc[item.date]) {
    acc[item.date] = { childrens: [item] };
    
    return acc;
  } 
  
  acc[item.date].childrens.push(item);

  return acc;
}, {});

console.log(items)

  • 1

    You already have a separate object, now you just need to use something like Object.entries with a map then turn the object into an array in the format you need. :)

  • 1

    Maybe this question can give you a general idea of how to do this. There are good alternatives there.

1 answer

5


Maybe it’s easier - at least I think - to do without reduce. Just make a loop simple by array old and go riding the new object:

const old = [
    { id: 1, date: '2020-08-27T00:00:00', title: 'Title 1' },
    { id: 2, date: '2020-08-27T00:00:00', title: 'Title 2' },
    { id: 3, date: '2020-08-25T00:00:00', title: 'Title 3' }
];

let items = {};
for (let i = 0; i < old.length; i++) {
    const e = old[i];
    const novoItem = { id: e.id, title: e.title};
    if (! items[e.date]) { // ainda não tem nada nesta data, criar um novo
        items[e.date] = { date: e.date, children: [ novoItem ]};
    } else { // já existe registro para a data, adiciona no array children já existente
        items[e.date].children.push(novoItem);
    }
}
console.log(items);

// ou, se quiser que items seja um array:
items = Object.values(items);
console.log(items);

That is, for each element in old I check if there is already an element corresponding to your date in items. If not, I create a new one, if I’ve already added it in the array children.

It just wasn’t clear which way to go, so I gave you two options. The first is an object whose keys are the dates and values are the objects containing the date and array of children:

{
  "2020-08-27T00:00:00": {
    "date": "2020-08-27T00:00:00",
    "children": [
      { "id": 1, "title": "Title 1" },
      { "id": 2, "title": "Title 2" }
    ]
  },
  "2020-08-25T00:00:00": {
    "date": "2020-08-25T00:00:00",
    "children": [
      { "id": 3, "title": "Title 3" }
    ]
  }
}

But in this case the date would be redundant. If the idea is to have an array (as it seems in the question example), just take only the values (Object.values(items)), and in that case would be:

[
  {
    "date": "2020-08-27T00:00:00",
    "children": [
      { "id": 1, "title": "Title 1" },
      { "id": 2, "title": "Title 2" }
    ]
  },
  {
    "date": "2020-08-25T00:00:00",
    "children": [
      { "id": 3, "title": "Title 3" }
    ]
  }
]

If you want, you can also change the for above by a for...of:

for (const e of old) {
    const novoItem = { id: e.id, title: e.title};
    if (! items[e.date]) { // ainda não tem nada nesta data, criar um novo
        items[e.date] = { date: e.date, children: [ novoItem ]};
    } else { // já existe registro para a data, adiciona no array children já existente
        items[e.date].children.push(novoItem);
    }
}

Or still, using allocation via structuring together with the scattering syntax:

let items = {};
for (const e of old) {
    const { date, ...novoItem } = { ...e };
    if (! items[date]) {
        items[date] = { date, children: [ novoItem ]};
    } else {
        items[date].children.push(novoItem);
    }
}

Do you really need reduce? It would look almost the same, but perhaps adding unnecessary complexity:

const old = [
    { id: 1, date: '2020-08-27T00:00:00', title: 'Title 1' },
    { id: 2, date: '2020-08-27T00:00:00', title: 'Title 2' },
    { id: 3, date: '2020-08-25T00:00:00', title: 'Title 3' }
];

let items = old.reduce(function(acc, item) {
  const newItem = { id: item.id, title: item.title };
  if (!acc[item.date]) {
    acc[item.date] = { date: item.date, children: [ newItem ] };
  } else {
    acc[item.date].children.push(newItem);
  }

  return acc;
}, {});
console.log(items);

// ou, se quiser que items seja um array:
items = Object.values(items);
console.log(items);

I don’t think you need reduce. Although the algorithm looks good, it adds a complexity that, although not so great so, in my opinion is unnecessary (create a function of callback which is called several times). If a for simple already solves, so that complicate?


<pedant mode>I also changed the name of the childrens for children, after all, "Children" is already in the plural.</pedantic mode>

  • 1

    Vlw mano! has done very well in answering, various ways to solve! Success!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.