Я пытаюсь запрограммировать достаточно быстрый алгоритм для объединения интервалов со значениями.
Например, есть 3 интервала (включая от и до):
{from:1, to: 3, amount: 1}
{from:5, to: 7, amount: 1}
{from:2, to: 6, amount: 1}
Результат:
{from:1, to: 1, amount: 1}
{from:2, to: 3, amount: 2}
{from:4, to: 4, amount: 1}
{from:5, to: 6, amount: 2}
{from:7, to: 7,amount: 1}
Когда число интервалов достигает 5000, тогда вычисления в моем алгоритме может занять около минуты. (в случае, когда каждый новый интервал слияния перекрывает большое количество других). Может быть, кто-то может посоветовать какой-то уже известный алгоритм, подходящий для этой задачи, или, может быть, он уже столкнулся с подобной проблемой и поделится своим решением?
input result
function mergeingIntervals(intervals: IInterval[]): IInterval[] {
//sort by length
intervals.sort((a, b) => b.to - b.from - a.to + a.from);
const result = [intervals[0]];
intervals.forEach(interval => addInterval(result, interval));
result.sort((a, b) => a.from - b.from);
return result;
}
function addInterval(result: IInterval[], interval: IInterval): void {
const firstIntersectionIndex = result.findIndex(row =>
row.from >= interval.from && row.to <= interval.to ||
row.from >= interval.from && row.from <= interval.to ||
row.from <= interval.from && row.to >= interval.to ||
row.to >= interval.from && row.to <= interval.to,
);
if (firstIntersectionIndex === -1) {
const indexToInsertInto = result.findIndex(row => row.from > interval.to);
if (indexToInsertInto !== -1) {
result.splice(indexToInsertInto, 0, interval);
} else {
result.unshift(interval);
}
} else {
const valueToMergeInto = result[firstIntersectionIndex];
if (valueToMergeInto.from <= interval.from && valueToMergeInto.to >= interval.to) {
const newIntervals: IInterval[] = [];
if (valueToMergeInto.from !== interval.from) {
newIntervals.push({
from: valueToMergeInto.from,
to: subtractHour(interval.from),
value: valueToMergeInto.value,
});
}
newIntervals.push({
from: interval.from,
to: interval.to,
value: interval.value + valueToMergeInto.value,
});
if (valueToMergeInto.to !== interval.to) {
newIntervals.push({
from: addHour(interval.to),
to: valueToMergeInto.to,
value: valueToMergeInto.value,
});
}
result.splice(firstIntersectionIndex, 1, ...newIntervals);
} else {
let count = 1;
result.slice(firstIntersectionIndex).forEach(sumValue => {
if (sumValue.to <= interval.to) {
count++;
return false;
} else {
return true;
}
});
if (count < 5) {
result.splice(firstIntersectionIndex, 1);
const newIntervals: IInterval[] = [];
if (interval.from < valueToMergeInto.from) {
newIntervals.push({
from: interval.from,
to: subtractHour(valueToMergeInto.from),
value: interval.value,
}, {
from: valueToMergeInto.from,
to: Math.min(valueToMergeInto.to, interval.to),
value: valueToMergeInto.value + interval.value,
});
if (interval.to !== valueToMergeInto.to) {
newIntervals.push({
from: addHour(Math.min(valueToMergeInto.to, interval.to)),
to: Math.max(valueToMergeInto.to, interval.to),
value: valueToMergeInto.to < interval.to ? interval.value : valueToMergeInto.value,
});
}
} else {
if (interval.from !== valueToMergeInto.from) {
newIntervals.push({
from: valueToMergeInto.from,
to: subtractHour(interval.from),
value: valueToMergeInto.value,
});
}
newIntervals.push({
from: interval.from,
to: Math.min(interval.to, valueToMergeInto.to),
value: interval.value + valueToMergeInto.value,
});
if (interval.to !== valueToMergeInto.to) {
newIntervals.push({
from: addHour(Math.min(valueToMergeInto.to, interval.to)),
to: Math.max(valueToMergeInto.to, interval.to),
value: valueToMergeInto.to < interval.to ? interval.value : valueToMergeInto.value,
});
}
}
newIntervals.forEach(period => addInterval(result, period));
} else {
const newIntervals: IInterval[] = [];
if (interval.from < valueToMergeInto.from) {
newIntervals.push({
from: interval.from,
to: subtractHour(valueToMergeInto.from),
value: interval.value,
}, {
from: valueToMergeInto.from,
to: Math.min(valueToMergeInto.to, interval.to),
value: interval.value,
});
if (interval.to !== valueToMergeInto.to) {
newIntervals.push({
from: addHour(Math.min(valueToMergeInto.to, interval.to)),
to: Math.max(valueToMergeInto.to, interval.to),
value: valueToMergeInto.to < interval.to ? interval.value : 0,
});
}
} else {
if (interval.from !== valueToMergeInto.from) {
newIntervals.push({
from: valueToMergeInto.from,
to: subtractHour(interval.from),
value: 0,
});
}
newIntervals.push({
from: interval.from,
to: Math.min(interval.to, valueToMergeInto.to),
value: interval.value,
});
if (interval.to !== valueToMergeInto.to) {
newIntervals.push({
from: addHour(Math.min(valueToMergeInto.to, interval.to)),
to: Math.max(valueToMergeInto.to, interval.to),
value: valueToMergeInto.to < interval.to ? interval.value : 0,
});
}
}
const valuesToMergeIntoArray = result.splice(firstIntersectionIndex, count, ...newIntervals);
valuesToMergeIntoArray.forEach(period => addInterval(interval, period));
}
}
}
}