2017-07-01 50 views
1

我有一個包含一些Javascript對象的數組。每個對象實際上是一個從畫布元素中拉出的水平線段。每個對象都具有屬性「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應該包含兩個數組(因爲有兩組相鄰的線段)。 yvalues爲132-136的線段將位於第一個數組中,而yvalues爲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}] 

] 

下面是我的代碼,我認爲這是接近的工作,但還沒有應用。通常情況下,排列陣列最終會變得完全不合邏輯。有空對象(不知道爲什麼?)和應該放在同一個數組中的線段不是。

由於該項目的性質,這需要在客戶端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並輸出json所需的文件 – user93

+0

@ user93請看最後兩個代碼片段。這是循環之前變量的內容,然後循環後內容應該是什麼樣子。沒有JSON真的發生了變化;它只是數組得到重組 – DanD

回答

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));

,所以我不得不因爲當輸入數組洗牌它並不總是返回相同的答案,修改我的代碼。現在很好。

我對這裏的遞歸迭代使用了一個非常不尋常的模式。如果您瞭解Haskell,在(x:xs)表單中表示數組是非常基礎的知識。 ES6也允許在JS中進行類似的模式匹配。我很有趣,直到我使用這個我沒有看到它在任何地方沒有書或博客。

所以這很簡單。如果你想總結所有數組的項目,你可以不喜歡

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

array destructuring將第一陣列項目(頭)分配給x變量和陣列的其餘部分(尾部)將被分配給...xsrest parameters作爲xs數組變量。換句話說,如果我提供sum功能[1,2,3,4],在第一輪x1xs[2,3,4]。所以你應該能夠遵循遞歸的其餘部分。

現在在這個答案中,我經常使用這種模式。然而,既然現在你知道它是什麼,你可以簡單地遵循邏輯。

的主要功能是getAdjacents,它有兩個實用輔助功能

  1. isAdjacent:它有兩個分段對象,並檢查它們是否相鄰或不相鄰。返回布爾值。
  2. groupBy:這一個取線段它們已經相鄰的第一個參數(這是as)的陣列,並且各自具有一個段對象(的rowarray最初尾部)爲[b,...bs]陣列的未經檢查的陣列的陣列。它會返回一個相鄰的元組,如[[{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