2017-07-01 10 views
1

私はいくつかのJavascriptオブジェクトを含む配列を持っています。各オブジェクトは、実際にはキャンバス要素から引かれた水平線分です。各オブジェクトは、プロパティ "lowx"(セグメントの左のx座標)、 "highx"(セグメントの右のx座標)、および "yvalue"(線分が占めるy座標水平)。隣接する行を1つの配列に結合する

隣接するすべての線分を同じ配列に結合するループが必要です。ここで配列変態だ:

はここ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は(二つの配列が含まれている必要があります隣接する線分の2つのグループ)。 y値が132〜136の線分は第1の配列にあり、y値が138〜140の線分は第2の配列になければなりません。

ので、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は完全に非論理的なものになります。 nullオブジェクトがあります(理由はわかりません)。同じ配列に配置する必要がある線分はありません。

これが対象とするプロジェクトの性質上、これはクライアント側の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

これは全く明確ではありません。現時点で何が起こっていますか?どうしたの? –

+0

入力jsonをspeficyしてください。必要な出力json – user93

+0

@ user93最後の2つのコードスニペットを見てください。これは、ループの前の変数の内容と、ループの後のコンテンツの外観です。実際にJSONが変更されることはありません。配列が再編成されるだけです。 – DanD

答えて

1

次のコードについては、それらがx軸上に交差する場合、2つのセグメントが隣接しており、彼らは隣接しているか同じ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));

入力配列がシャッフルされたとき、それは常に同じ答えを返していなかったので、だから私は私のコードを変更する必要がありました。今は大丈夫です。

ここで私の再帰的反復には非常に珍しいパターンを使用しています。 (x:xs)フォームで配列を表現することは、Haskellを知っていればかなり基本的な知識です。 ES6では、JSでも同様のパターンマッチングが可能です。私はこれを使うまで面白いです。私は本やブログでもどこにも見たことがありません。

とても簡単です。あなたはすべての配列項目を合計したい場合は、...xsに割り当てられますx変数や配列の残りの部分(テール)に最初の配列項目(ヘッド)を割り当てます

function sum([x,...xs]){ 
    return xs.length ? x + sum(xs) : x; 
} 

array destructuringのように行うことができます配列変数のxsとしてrest parameters。言い換えれば、sumの機能を[1,2,3,4]と入力した場合、最初のターンでx1で、xs[2,3,4]です。だからあなたは残りの再帰に従うことができるはずです。

ここで私はこのパターンを頻繁に使用しています。しかし今から、あなたはそれが何であるかを知っているので、単に論理に従うことができます。

主な機能は、getAdjacentsであり、それは、二つのユーティリティヘルパー機能

  1. isAdjacentを有する:それらは隣接かである場合には、二つのセグメントオブジェクト及びチェックを取ります。ブール値を返します。
  2. groupBy:この1つは既に(asある)最初の引数と[b,...bs]などの単一セグメントオブジェクト(当初rowarrayの尾部)とアレイの各未確認配列のアレイとして隣接するラインセグメントの配列をとります。そしてそれは隣接するタプルを返します。[[{adj. segment}{adj. segment}...{adj. segment}],[[{segment}],[{segment}],...,[{segment}]]]のように隣接しません。

あなたはコメントされている主な機能の本体で続けることができるはずです。

+0

これは私が必要としたものです!本当にありがとう! – DanD

+0

ちょっと - それほど問題がなければ、各行が何をしているのか、その背後にあるロジックを指定するコメントをいくつか追加できますか? – DanD

+0

@DanD申し訳ありませんが、ちょうどそれを動作させる時間があります。私はそれを少し変更しました。今それは非常にしっかりしているようです。私は私の答えとコメントにコメントを追加しました。あなたが抱えているものがあるかどうか尋ねてください。 – Redu

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)

+0

これは私が書いた例の配列で動作しますが、これは単なる例です。特定のシナリオでは、rowarrayの内容はユーザによって生成されるので、ループは任意の量のグループで動作する必要があります(特定のxとyの値に基づいてフィルタリングすることはできません。xとyの値何でもかまいません)。私は完全に独学で勉強していますので、それがどのように機能しているかについてのコメントを提供できれば便利です。 – DanD

+0

必要に応じて、値132,146,138,140を動的に置き換えることができます。 – user93

+0

オブジェクトの配列としてグループを持っている場合は、それをマップして、上記のコード – user93

1

を使用して結果を得ることができます - 「隣接」であるかのセグメントが、あなたはconnected-component labelingようなものが必要と思われます(セルではなくセグメントで)union-find algorithmの種類を実装する必要があり、disjoint set data structureとなります。

この問題は、計算幾何学から矩形組合問題として考えることができる(ユニオン・検索および/またはスイープラインアプローチにより解決)

関連する問題