Отфильтруйте массив объектов по ключу и вложенному значению в JavaScript

#javascript #arrays #object

#язык JavaScript #массивы #объект

Вопрос:

У меня есть массив объектов, относящихся к событиям. События организованы по ключу/значению, где Ключом является дата начала месяца, а значением является массив или объекты, которые имеют определенное время в течение этого месяца.

 allEvents = [  {  key: "Dec 2021",  value: [  { id: 0, date: "Dec 06 2021" },  { id: 1, date: "Dec 01 2021" },  ],  },  {  key: "Nov 2021",  value: [  { id: 0, date: "Nov 27 2021" },  { id: 1, date: "Nov 23 2021" },  { id: 2, date: "Nov 10 2021" },  ],  },  {  key: "Oct 2021",  value: [  { id: 0, date: "Oct 27 2021" },  { id: 1, date: "Oct 23 2021" },  { id: 2, date: "Oct 10 2021" },  ],  }, ];  

Мне нужно отфильтровать эти события по заданному диапазону дат, например, 15 ноября 2021 года — 04 декабря 2021 года

Это должно отфильтровать объект октября, а также любые события, которые попадают в данный диапазон дат, сохраняя при этом родительский объект. Таким образом, результат был бы:

 filteredEvents = [  {  key: "Dec 2021",  value: [  { id: 1, date: "Dec 01 2021" },  ],  },  {  key: "Nov 2021",  value: [  { id: 0, date: "Nov 27 2021" },  { id: 1, date: "Nov 23 2021" },  ],  }, ];  

До сих пор я выполнял фильтрацию на уровне месяца, как показано ниже, но не могу понять, как работать на уровне дня.

 const dateRange = ["Nov 15 2021", "Dec 04 2021"]; const min = dateRange[0].getTime(); const max = dateRange[1].getTime();  const filteredEvents = allEvents.filter(  eventGroup =gt; new Date(eventGroup.key).getTime() gt;= min amp;amp; new Date(eventGroup.key).getTime() lt;= max);  

В идеале хотелось бы просто использовать ES6, но можно использовать lodash.

Ответ №1:

Это выглядит немного громоздко, но довольно просто. Во-первых, map ваш массив и отфильтруйте все value.date , что не вписывается в диапазон. Затем просто отфильтруйте все родительские элементы, которые имеют массив значений нулевой длины.

 const filteredEvents = (from, to) =gt; allEvents  .map( g =gt;   ({...g,   value: g.value.filter(f =gt;   new Date(f.date).getTime() gt;= new Date(from).getTime() amp;amp;   new Date(f.date).getTime() lt;= new Date(to).getTime())  }))  .filter(f =gt; f.value.lengthgt;0);  
 let allEvents = [{  key: "Dec 2021",  value: [{  id: 0,  date: "Dec 06 2021"  },  {  id: 1,  date: "Dec 01 2021"  },  ],  },  {  key: "Nov 2021",  value: [{  id: 0,  date: "Nov 27 2021"  },  {  id: 1,  date: "Nov 23 2021"  },  {  id: 2,  date: "Nov 10 2021"  },  ],  },  {  key: "Oct 2021",  value: [{  id: 0,  date: "Oct 27 2021"  },  {  id: 1,  date: "Oct 23 2021"  },  {  id: 2,  date: "Oct 10 2021"  },  ],  }, ];   const filteredEvents = (from, to) =gt; allEvents  .map( g =gt; ({...g, value: g.value.filter(f =gt; new Date(f.date).getTime() gt;= new Date(from).getTime() amp;amp; new Date(f.date).getTime() lt;= new Date(to).getTime())})).filter(f =gt; f.value.lengthgt;0);  console.log(filteredEvents("Nov 15 2021", "Dec 04 2021")); 

Комментарии:

1. Это здорово. Я подходил к проблеме слишком линейно… фильтрация по месяцам, затем по дням. Хороший крик, чтобы просто отфильтровать дни, а затем удалить пустые месяцы.

Ответ №2:

во-первых,,

 const min = dateRange[0].getTime(); const max = dateRange[1].getTime();  

должно быть:

 const min = new Date(dateRange[0]).getTime(); const max = new Date(dateRange[1]).getTime();  

Затем, после начального цикла, я бы сделал карту, чтобы удалить элементы из value . Логика была бы очень похожа на фильтр, который у вас уже есть.

Ответ №3:

Значения для каждого события имеют полную дату. Используйте их, чтобы исключить даты за пределами диапазона, а затем исключить любые события без значений.

 const allEvents = [  {  key: "Dec 2021",  value: [  { id: 0, date: "Dec 06 2021" },  { id: 1, date: "Dec 01 2021" },  ],  },  {  key: "Nov 2021",  value: [  { id: 0, date: "Nov 27 2021" },  { id: 1, date: "Nov 23 2021" },  { id: 2, date: "Nov 10 2021" },  ],  },  {  key: "Oct 2021",  value: [  { id: 0, date: "Oct 27 2021" },  { id: 1, date: "Oct 23 2021" },  { id: 2, date: "Oct 10 2021" },  ],  }, ];  const dateRange = ["Nov 15 2021", "Dec 04 2021"]; const [min, max] = dateRange.map(d =gt; new Date(d).getTime());  const filteredEvents = allEvents.map(({key,value}) =gt; ({  key,  value:value.filter(({date:d}) =gt;   new Date(d).getTime() gt;= min amp;amp; new Date(d).getTime() lt;= max) })) .filter(({value:v}) =gt; v.length);   console.log( filteredEvents );