想象一下类似物品网格的东西。 用户可以在网格中选择多个范围的项目。当有多个范围(选择)时,我想确定最后创建的范围是否与现有范围重叠。 可以将网格系统与文本区域中的字符进行比较,在那里可以突出显示多个文本范围。
范围存储为:
{
'rangeStartLineIndex': 2,
'rangeStartColIndex': 9,
'rangeEndLineIndex': 4,
'rangeEndColIndex': 7
}
以上范围可以在图像中显示。但是请注意,网格的行数和列数不是恒定的。
目标是遍历现有范围,并查看刚创建的范围是否与现有范围重叠(或完全适合)。如果是这样,则采用该现有范围,并对其进行扩展,以使创建的范围与与其重叠的范围合并。因此,这是一种规范化数据。
另一个代码示例:
var ranges = []; // stores the range objects that are created earlier.
var createdRange = {...}; // range object just created.
for(var i = 0; i < ranges; i++) {
var overlap = doesThisOverlap(createdRange, ranges[i]);
if(overlap) {
// overlaps, which means we extend the existing range.
range[i].rangeStartLineIndex = Math.min(range[i].rangeStartLineIndex, createdRange.rangeStartLineIndex);
range[i].rangeStartColIndex = Math.min(range[i].rangeStartColIndex, createdRange.rangeStartColIndex);
range[i].rangeEndLineIndex = Math.max(range[i].rangeEndLineIndex, createdRange.rangeEndLineIndex);
range[i].rangeEndColIndex = Math.max(range[i].rangeEndColIndex, createdRange.rangeEndColIndex);
} else {
// means the new range does not extend an existing range, so add it.
ranges.push(createdRange);
}
}
function doesThisOverlap(rangeA, rangeB) {
// ???
}
当尝试实现功能doesThisOverlap
时,我最终遇到了过多的if块。我感到困惑,也是因为我感觉找到了一种算法。
我还尝试了将范围起始点的行和col索引相加,以赋予它一个“分数”(并对其端点的行和列索引进行相同的操作)。 然后比较范围之间的起点/终点得分。
答案 0 :(得分:2)
问题不是真正的2D,如果将范围表示为
,则变得更加容易{
rangeStart: 29,
rangeEnd:48
}
您可以通过计算
转换为该表示形式lineIndex * COLUMN_NUMBER + columnIndex.
基本上,您应该迭代所有范围并找到min rangeStart和rangeEnd。然后,您可以使用以下方法将结果转换为列/行:
columnIndex = x % COLUMN_NUMBER;
lineIndex = parseInt(x / COLUMN_NUMBER).
答案 1 :(得分:1)
识别createdRange
是否与ranges
之一重叠的一种方法是给每个range
起始索引和结束索引,然后检查{{ 1}}是否与其他范围的索引重叠。
首先,让我们从提高可读性的角度更改createdRange
对象的形状:
range
将此{
start: { row: 2, col: 9 },
end: { row: 4, col: 7 }
}
对象与您定义的对象的映射很简单:
range
顺便说一句,我首先要指出逻辑上的一个小错误。
在rangeStartLineIndex => start.row
rangeStartColIndex => start.col
rangeEndLineIndex => end.row
rangeEndColIndex => end.col
循环中,您正在检查for
是否与当前createdRange
重叠。如果不是,则您要将该range
添加到Ranges数组。
但是,您只需要在createdRange
中添加createdRange
如果没有一个范围与ranges
因此,正确的createdRange
循环如下所示:
for
好的,现在让我们看看如何计算给定范围的索引。
如果我们开始在网格中从左到右分配索引(从0开始),
简单的数学说,var hasOverlap = false; // this will tell if any of the ranges overlap
for(var i = 0; i < ranges; i++) {
var overlap = doesThisOverlap(createdRange, ranges[i]);
if(overlap) {
// overlaps, which means we extend the existing range.
// some logic to update the overlapped ranges
hasOverlap = true; // a range has overlapped, set the flag to true
break;
}
}
// Did we see any overlap?
if(!hasOverlap) {
// no we did not, let us add this range to ranges array
// means the new range does not extend an existing range, so add it.
ranges.push(createdRange);
}
行和r
列中框的索引为:
c
以下是帮助程序功能,可以帮助计算给定范围内的索引:
index = r * (COL + 1) + c [COL is the total number of columns in the grid]
请注意,function getIndex(row, col, COL) {
return row * (COL + 1) + col;
}
function getIndices(range) {
var start = range.start;
var end = range.end;
var startIndex = getIndex(start.row, start.col, COLS);
var endIndex = getIndex(end.row, end.col, COLS);
return { start: startIndex, end: endIndex };
}
采用getIndices
并输出具有range
和start
索引的对象。现在,我们可以计算end
和当前createdRange
的索引。根据索引,我们将知道范围是否重叠。
问题现在可以归结为:
我们有一条线AB,并给定了新的线PQ,找出新线PQ是否与AB重叠。 (其中A,B,P,Q是数字线上的点,A
拿笔和纸画几条线。您会知道,行不会重叠的情况只有两种情况:
将此观察结果映射到我们的range
对象上,我们可以这样说:
range
这就是代码中的样子:
P => createdRange.startIndex
Q => createdRange.endIndex
A => currentRange.startIndex
B => currentRange.endIndex
请注意,我们摆脱了功能var createdRangeIndices = getIndices(createdRange);
var hasOverlap = false;
for (var i = 0; i < ranges.length; i++) {
var currentRangeIndices = getIndices(ranges[i]);
var overlap = (createdRangeIndices.end < currentRangeIndices.start)
|| (currentRangeIndices.end < createdRangeIndices.start);
if (!overlap) {
// overlaps, which means we extend the existing range.
// some logic to update the overlapped ranges
hasOverlap = true;
break;
}
}
if (!hasOverlap) {
// means the new range does not extend an existing range, so add it.
ranges.push(createdRange);
}
。一个简单的标志就可以。
如果重叠,现在剩下的就是更新doesThisOverlap
的逻辑。
您已经在问题中弄清楚了其中的一部分。我们采用起始索引的最小值和终止索引的最大值。这是该代码:
range
完成!
这是将所有点滴结合在一起的完整代码:
for (var i = 0; i < ranges.length; i++) {
var currentRangeIndices = getIndices(ranges[i]);
var overlap = (createdRangeIndices.end < currentRangeIndices.start)
|| (currentRangeIndices.end < createdRangeIndices.start);
if (!overlap) {
// overlaps, which means we extend the existing range.
// some logic to update the overlapped ranges
var start, end;
if (currentRangeIndices.start < createdRangeIndices.start) {
start = ranges[i].start;
} else {
start = createdRange.start;
}
if (currentRangeIndices.end > createdRangeIndices.end) {
end = ranges[i].end;
} else {
end = createdRange.end;
}
ranges[i] = { start: start, end: end };
hasOverlap = true;
break;
}
}