Сортировка массива диапазонов дат по группам, в которых каждая группа не имеет перекрывающихся диапазонов (Javascript) - PullRequest
0 голосов
/ 06 мая 2020

У меня есть массив объектов, и каждый объект имеет дату начала и дату окончания.

sortedDateRanges = [
    {
    id: 1,
    start: "2018-01-01",
    end: "2018-01-05",
    name: "First item"
  },
  {
    id: 2,
    start: "2018-01-02",
    end: "2018-01-08",
    name: "Second item"
  },
  {
    id: 3,
    start: "2018-01-06",
    end: "2018-01-13",
    name: "Third item"
  },
  {
    id: 4,
    start: "2018-01-14",
    end: "2018-01-14",
    name: "Fourth item"
  },
  {
    id: 5,
    start: "2018-02-01",
    end: "2018-02-15",
    name: "Fifth item"
  },
]

Мне нужно отсортировать эти объекты по группам, в каждой группе которых нет перекрывающихся диапазонов дат . Определенно есть несколько допустимых выходов. [[{id: 1},{id: 3},{id: 4}], [{id: 2},{id: 5}]] или [[{id: 1}, {id: 3}, {id: 5}], [{id: 2}, {id: 4}]] et c.

Мое текущее решение просто сравнивает каждый диапазон с предыдущим диапазоном, который не дает неправильное решение ... это просто не комплексное решение, которое я ищу. Мое текущее решение возвращает [[{id: 1}],[{id: 2}],[{id: 3}, {id: 4}, {id: 5}]]

export const groupUnoverlappedItems = sortedDateRanges => {
    let groups = [];
    let rangeIds = [];

    sortedDateRanges.map((current, idx, arr) => {
        if (idx === 0) {
            groups.push([current]);
            rangeIds.push(current.id);
            // return result;
        } else {
            let previous = arr[idx -1];

            // check for overlap
            let previousEnd = (new Date(previous.end)).getTime();
            let currentStart = (new Date(current.start)).getTime();
            let overlap = (previousEnd >= currentStart);

            if (overlap) {
                // if overlap, push new group
                groups.push([current]);
                rangeIds.push(current.id);
            } else if (rangeIds.indexOf(current.id) === -1) {
                groups[groups.length -1].push(current);
                rangeIds.push(current.id);
            }
        }
    });

    return groups;
};

1 Ответ

0 голосов
/ 06 мая 2020

Я не понимаю, есть ли у вас правило для определения групп, или они должны формироваться динамически.

В любом случае, почему бы вам не получить объект с самой ранней датой начала и не использовать его чтобы создать первый объект в первой группе.

У вас есть начальная точка, затем вы можете найти объект с ближайшей датой начала, которая не перекрывает дату окончания вашего первого объекта. Если вы будете действовать последовательно, как только вы найдете дату, которая пересекается, вы можете быть почти уверены, что это хорошая дата для формирования следующей группы.

Как только вы не найдете других кандидатов для первой группы, вы можете проверить, существует ли другая группа (и есть ли в ней хотя бы объект), а затем повторять процесс, пока не будут выделены все объекты.

Могу я предложить использовать библиотеку, например date-fns , которая поможет вам с помощью полезных методов для управления датами, а также для определения интервалов дат. Javascript имеет базовую c поддержку дат, использование библиотеки может сэкономить вам много времени;)

...