我有一个包含一些Javascript对象的数组。每个对象实际上是从canvas元素中提取的水平线段。每个对象都具有属性“lowx”(段的左x坐标),“highx”(段的右x坐标)和“yvalue”(线段占据的y坐标,因为它是水平)。
我需要一个将所有相邻线段组合到同一个数组中的循环。这是一个示例数组转换:
以下是在运行此循环之前rowarray的示例:
var rowarray = [
[{"lowx": 210, "highx": 212, "yvalue": 132}],
[{"lowx": 208, "highx": 214, "yvalue": 133}],
[{"lowx": 207, "highx": 215, "yvalue": 134}],
[{"lowx": 207, "highx": 216, "yvalue": 135}],
[{"lowx": 206, "highx": 216, "yvalue": 136}],
[{"lowx": 206, "highx": 216, "yvalue": 138}],
[{"lowx": 205, "highx": 220, "yvalue": 139}],
[{"lowx": 199, "highx": 209, "yvalue": 140}]
]
在遍历循环之后,rowarray应该包含两个数组(因为有两组相邻的线段)。 y值为132-136的线段位于第一个数组中,y值为138-140的线段应位于第二个数组中。
因此,rowarray看起来像:
var rowarray = [
[{"lowx": 210, "highx": 212, "yvalue": 132},
{"lowx": 208, "highx": 214, "yvalue": 133},
{"lowx": 207, "highx": 215, "yvalue": 134},
{"lowx": 207, "highx": 216, "yvalue": 135},
{"lowx": 206, "highx": 216, "yvalue": 136}],
[{"lowx": 206, "highx": 216, "yvalue": 138},
{"lowx": 205, "highx": 220, "yvalue": 139},
{"lowx": 199, "highx": 209, "yvalue": 140}]
]
这是我所拥有的代码,我认为它已接近工作,但尚未完成。通常它的rowarray最终会成为完全不合逻辑的东西。有空对象(不知道为什么?)和应该放在同一个数组中的线段不是。
由于项目的性质,这需要在客户端javascript中完成。但是,使用JQuery很好并受到欢迎。
var keepgoing = 1;
var errorcounter = 0;
while (keepgoing == 1) {
try {
hadtocombine = 0;
for (var x = rowarray.length-1; x >= 0; x--) {
for (var w = rowarray.length-1; w >= 0; w--) {
for (var q = rowarray[x].length-1; q >= 0; q--) {
for (var z = rowarray[w].length-1; z >= 0; z--) {
if ((rowarray[x][q].yvalue == (rowarray[w][z].yvalue + 1)) || (rowarray[x][q].yvalue == (rowarray[w][z].yvalue - 1))) {
if ((rowarray[x][q].highx >= rowarray[w][z].lowx) && (rowarray[x][q].highx <= rowarray[w][z].highx)) {
rowarray.splice(w,1);
rowarray.splice(x,1);
rowarray.push(rowarray[x].concat(rowarray[w]));
hadtocombine = 1;
}
else if ((rowarray[x][q].lowx >= rowarray[w][z].lowx) && (rowarray[x][q].lowx <= rowarray[w][z].highx)) {
rowarray.splice(w,1);
rowarray.splice(x,1);
rowarray.push(rowarray[x].concat(rowarray[w]));
hadtocombine = 1;
}
else if ((rowarray[x][q].highx >= rowarray[w][z].highx) && (rowarray[x][q].lowx <= rowarray[w][z].lowx)) {
rowarray.splice(w,1);
rowarray.splice(x,1);
rowarray.push(rowarray[x].concat(rowarray[w]));
hadtocombine = 1;
}
else if ((rowarray[x][q].lowx >= rowarray[w][z].lowx) && (rowarray[x][q].highx <= rowarray[x][q].highx)) {
rowarray.splice(w,1);
rowarray.splice(x,1);
rowarray.push(rowarray[x].concat(rowarray[w]));
hadtocombine = 1;
}
}
}
}
}
}
if (hadtocombine == 0) {
keepgoing = 0;
}
} catch (err) { errorcounter++; if(errorcounter >= 20000) { keepgoing = 10; } }
}
希望我能够很好地解释这一点 - 如果没有评论,我会修改。这是我的第一篇文章(经过多年的潜伏),所以我希望我已经做好了。
谢谢!
答案 0 :(得分:1)
您可以使用简单的过滤器和地图方法
来实现结果
var rowarray = [
[{
"lowx": 210,
"highx": 212,
"yvalue": 132
}],
[{
"lowx": 208,
"highx": 214,
"yvalue": 133
}],
[{
"lowx": 207,
"highx": 215,
"yvalue": 134
}],
[{
"lowx": 207,
"highx": 216,
"yvalue": 135
}],
[{
"lowx": 206,
"highx": 216,
"yvalue": 136
}],
[{
"lowx": 206,
"highx": 216,
"yvalue": 138
}],
[{
"lowx": 205,
"highx": 220,
"yvalue": 139
}],
[{
"lowx": 199,
"highx": 209,
"yvalue": 140
}]
]
const group = [{
l: 132,
h: 136
},
{
l: 138,
h: 140
}
];
rowarray = rowarray.map(x => x[0])
const limit = (h, l, x) => x.yvalue <= h || x.yvalue <= l
let gg = [];
group.map(g => {
gg.push(rowarray.filter(x => limit(g.l, g.h, x)))
});
console.log(gg)
答案 1 :(得分:1)
您没有明确说明 - 哪些细分是&#34;相邻&#34;,但似乎您需要类似connected-component labeling的内容(使用细分而不是细胞)并且需要实现一种{{3} },制作union-find algorithm。
此问题也可以被视为计算几何中的矩形联合问题(通过联合查找和/或扫描线方法求解)
答案 2 :(得分:1)
对于以下代码,如果两个段在x轴上相交并且它们在相邻或相同的y值上,则它们是相邻的。
解决方案如下;
function getAdjacents([x,...xs], r = []){ // x is the first item and xs is the rest of the input array.
function isAdjacent(a,b){
return (a.lowx < b.highx && b.lowx < a.highx) && Math.abs(a.yvalue - b.yvalue) < 2;
}
function groupBy(as, [b,...bs], r = [[],[]]){
as.some(a => isAdjacent(a,b[0])) ? r[0].push(b[0]) : r[1].push(b);
return bs.length ? groupBy(as.concat(r[0]), bs, r)
: r;
}
var [as,bs] = xs.length ? groupBy(x,xs) : [[],[]], // group the rest according to the first element
cs = x.concat(as); // first element and it's adjacent elements
return bs.length ? as.length ? getAdjacents([cs].concat(bs),r) // if adjacent elements are found then keep checking
: (r.push(cs), getAdjacents(bs,r)) // if not push previous adjacents into result and start with the remaining
: (r.push(cs), r); // if no more remaining return result
}
var rowarray = [[{"lowx": 210, "highx": 212, "yvalue": 132}],
[{"lowx": 208, "highx": 214, "yvalue": 133}],
[{"lowx": 207, "highx": 215, "yvalue": 134}],
[{"lowx": 207, "highx": 216, "yvalue": 135}],
[{"lowx": 206, "highx": 216, "yvalue": 136}],
[{"lowx": 206, "highx": 216, "yvalue": 138}],
[{"lowx": 205, "highx": 220, "yvalue": 139}],
[{"lowx": 199, "highx": 209, "yvalue": 140}]
];
console.log(getAdjacents(rowarray));
&#13;
所以我不得不修改我的代码,因为当输入数组被洗牌时它总是没有返回相同的答案。现在好了。
我在这里使用一种非常不寻常的模式进行递归迭代。如果您了解Haskell,那么以(x:xs)
形式表达数组是非常基本的知识。 ES6也允许在JS中进行类似的模式匹配。我很有趣,直到我使用它,我没有在任何书籍或博客中看到它。
所以它非常简单。如果你想要总结你可能喜欢的所有数组项目
function sum([x,...xs]){
return xs.length ? x + sum(xs) : x;
}
array destructuring会将第一个数组项(head)分配给x
变量,数组的其余(尾部)将分配给...xs
rest parameters作为xs
数组变量。换句话说,如果我使用sum
向[1,2,3,4]
函数提供信息,则第一个回合x
为1
,xs
为[2,3,4]
。所以你应该能够跟随递归的其余部分。
现在在这个答案中,我经常使用这种模式。但是既然现在你知道它是什么,你可以简单地遵循逻辑。
主要功能是getAdjacents
,它有两个实用助手功能
isAdjacent
:它需要两个段对象并检查它们是否相邻。返回布尔值。groupBy
:这个作为第一个参数(即as
)已经相邻的一系列线段和一个未经检查的数组数组,每个数组都有一个段对象( rowarray
最初的尾部)为[b,...bs]
。它会返回一个相邻的元组,而不是像[[{adj. segment}{adj. segment}...{adj. segment}],[[{segment}],[{segment}],...,[{segment}]]]
那样相邻。任何你应该能够继续使用被评论的主要功能的主体。