#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 );