JavaScript Flat one dimensional array to tree

人走茶凉 提交于 2020-06-16 17:24:28

问题


I have following objects stacked in a 1D array:

var colors = ["#FF0000", "#00FF00", "#0000FF", "#FF00FF", "#00FFFF"];

var array1D = [

    { level: 1, x: 0, y: 0 },
    { level: 1, x: 0, y: 1 },
    { level: 1, x: 1, y: 0 },
    { level: 4, x: 8, y: 8 },
    { level: 4, x: 8, y: 9 },
    { level: 5, x: 18, y: 16 },
    { level: 5, x: 18, y: 17 },
    { level: 5, x: 19, y: 16 },
    { level: 5, x: 19, y: 17 },
    { level: 5, x: 18, y: 18 },
    { level: 5, x: 18, y: 19 },
    { level: 5, x: 19, y: 18 },
    { level: 5, x: 19, y: 19 },
    { level: 4, x: 8, y: 10 },
    { level: 4, x: 8, y: 11 },
    { level: 5, x: 18, y: 20 },
    { level: 5, x: 18, y: 21 },
    { level: 5, x: 19, y: 20 },
    { level: 5, x: 19, y: 21 },
    { level: 4, x: 9, y: 11 },
    { level: 5, x: 20, y: 16 },
    { level: 5, x: 20, y: 17 },
    { level: 5, x: 21, y: 16 },
    { level: 5, x: 21, y: 17 },
    { level: 5, x: 20, y: 18 },
    { level: 5, x: 20, y: 19 },
    { level: 5, x: 21, y: 18 },
    { level: 5, x: 21, y: 19 },
    { level: 4, x: 11, y: 8 },
    { level: 5, x: 22, y: 18 },
    { level: 5, x: 22, y: 19 },
    { level: 5, x: 23, y: 18 },
    { level: 5, x: 23, y: 19 },
    { level: 5, x: 20, y: 20 },
    { level: 5, x: 20, y: 21 },
    { level: 5, x: 21, y: 20 },
    { level: 5, x: 21, y: 21 },
    { level: 4, x: 10, y: 11 },
    { level: 5, x: 22, y: 20 },
    { level: 5, x: 22, y: 21 },
    { level: 5, x: 23, y: 20 },
    { level: 5, x: 23, y: 21 },
    { level: 4, x: 11, y: 11 },
    { level: 2, x: 2, y: 3 },
    { level: 2, x: 3, y: 2 },
    { level: 2, x: 3, y: 3 }

];

It's basically a quadtree structure, so you don't need to validate if you can build a tree from it or not.

Visually it looks like following illustration:

enter code here

The code for viz is very simple:

quad.sort(function(a_, b_){ return a_.level - b_.level; })
var canvas = document.createElement("canvas");
document.body.appendChild(canvas)
canvas.width = 512;
canvas.height = 512;
var ctx = canvas.getContext("2d");

quad.forEach(function(node_){

    ctx.fillStyle = colors[node_.level - 1];
    var w = 256;
    for(var i = 0; i < node_.level; i++) { w /= 2; }
    var x = 256;
    for(var i = 0; i < node_.level; i++) { x /= 2; }
    x *= node_.x;
    var y = 256;
    for(var i = 0; i < node_.level; i++) { y /= 2; }
    y *= node_.y;

    ctx.fillRect(x + 1,  y + 1, w - 2, w - 2);

});

The task is to build a tree out of these nodes in a fastest way as possible to get something like this:

var result = [

    {id: "0.1", children: null },
    {id: "0.2", children: null },
    {id: "0.3", children: null },
    {id: "0.4", children: [

        { id: "0.1.1", children: [

            ...

        ] },
        { id: "0.1.2", children: [] },
        { id: "0.1.3", children: [] },
        { id: "0.1.4", children: [] },

    ] }

];

UPDATE:

ID's are generating by this logic—top-left is 1, top-right is 2, bottom-left is 3, bottom-right is 4.

So, i.e. left green square at the bottom is 4.3, its neighbour to the right is 4.4. The first magenta square is 4.1.1.

In initial 1D array level, x and y values are in charge of positioning and scaling partitions, so you could always get its level and parents by these values.

All I need to convert 1D array to 2D tree by using these level, x and y values.


回答1:


I am trying to understand and to build it, I have a solution that seems to work, but requires the levels not to "jump" (i.e. be continuous), so in your example, there is no level 3, is that valid? I created a slightly simplified example to show how this can work for continuous levels:

const colors = ["#FF0000", "#00FF00", "#0000FF", "#FF00FF", "#00FFFF"];

const array1D = [
    { level: 1, x: 0, y: 0 },
    { level: 1, x: 16, y: 0 },
    { level: 1, x: 0, y: 16 },    
      //*    
        //*
        { level: 3, x: 16, y: 16 },  
        { level: 3, x: 20, y: 16 },
        { level: 3, x: 16, y: 20 },  
        { level: 3, x: 20, y: 20 }, 
        //*/    
      { level: 2, x: 24, y: 16 },
      { level: 2, x: 16, y: 24 },
      { level: 2, x: 24, y: 24 }    
      //*
];

const arrayNested = createdNestedQuadTree(array1D);
console.log(arrayNested);

function createdNestedQuadTree(input, level) {
  const nestedOutput = [];
  //don't mutate input, call with shallow copy:
  innerRecursive([...input], nestedOutput);
  
  function innerRecursive(currArr, parentArr, level){
    const currentLevel = level || 1;
    const currentChildren = [];
    const pointOfNesting = {};
    for (let i of [1,2,3,4]){      
      const item = currArr[i-1];
      //console.log(currentLevel, i, item);
      if (currentLevel == item.level){
        item.id = `${currentLevel}.${i}`;
        item.children = null;
        parentArr.push(item);
        //console.log('output', nestedOutput);
      }
      else {        
        pointOfNesting.id = `${currentLevel}.${i}`;
        pointOfNesting.children = [];
        parentArr.push(pointOfNesting);
        //console.log('parent', parentArr); 
        
        let child = currArr[i-1];
        let j = i - 1;
        let position = 1;
        //console.log(child);

        while (child && child.level > currentLevel){
          //console.log('child', child);
          currentChildren.push(child);
          j +=1;
          child = currArr[j];         
        }        
        currArr.splice(i-1, (j - (i-1) ) );
        currArr.splice(i-1, 0, pointOfNesting);

        //console.log('curr', currArr);
        //console.log('parent', parentArr); 
        //console.log('children', currentChildren);
        //console.log('output', nestedOutput);
        innerRecursive([...currentChildren], pointOfNesting.children, currentLevel + 1)
      }      
    }
    
  }  
  return nestedOutput;
}
.as-console-wrapper { max-height: 100% !important; top: 0; }

Output:

[
  {
    "level": 1,
    "x": 0,
    "y": 0,
    "id": "1.1",
    "children": null
  },
  {
    "level": 1,
    "x": 16,
    "y": 0,
    "id": "1.2",
    "children": null
  },
  {
    "level": 1,
    "x": 0,
    "y": 16,
    "id": "1.3",
    "children": null
  },
  {
    "id": "1.4",
    "children": [
      {
        "id": "2.1",
        "children": [
          {
            "level": 3,
            "x": 16,
            "y": 16,
            "id": "3.1",
            "children": null
          },
          {
            "level": 3,
            "x": 20,
            "y": 16,
            "id": "3.2",
            "children": null
          },
          {
            "level": 3,
            "x": 16,
            "y": 20,
            "id": "3.3",
            "children": null
          },
          {
            "level": 3,
            "x": 20,
            "y": 20,
            "id": "3.4",
            "children": null
          }
        ]
      },
      {
        "level": 2,
        "x": 24,
        "y": 16,
        "id": "2.2",
        "children": null
      },
      {
        "level": 2,
        "x": 16,
        "y": 24,
        "id": "2.3",
        "children": null
      },
      {
        "level": 2,
        "x": 24,
        "y": 24,
        "id": "2.4",
        "children": null
      }
    ]
  }
]

Corresponding to this quadtree (32 x 32):

Here is a more complex example (but again continuous):

const colors = ["#FF0000", "#00FF00", "#0000FF", "#FF00FF", "#00FFFF"];

const array1D = [     
    { level: 1, x: 0, y: 0 },
    { level: 1, x: 16, y: 0 },
    { level: 1, x: 0, y: 16 },      
      //* <level 2>    
        //* <level 3>
        { level: 3, x: 16, y: 16 },     
          //* <level 4>
          { level: 4, x: 20, y: 16 },
            //* <level 5> 
            { level: 5, x: 22, y: 16 },
            { level: 5, x: 23, y: 16 },
            { level: 5, x: 22, y: 17 },
            { level: 5, x: 23, y: 17 },
            //*/ </level 5>   
          { level: 4, x: 20, y: 18 },
          { level: 4, x: 22, y: 18 },
          //*/ </level 4>    
        { level: 3, x: 16, y: 20 },  
        { level: 3, x: 20, y: 20 },      
        //*/ </level 3>    
      { level: 2, x: 24, y: 16 },
      { level: 2, x: 16, y: 24 },
      { level: 2, x: 24, y: 24 }   
      //* </level 2>
];

const arrayNested = createdNestedQuadTree(array1D);
console.log(arrayNested);

function createdNestedQuadTree(input, level) {
  const nestedOutput = [];
  //don't mutate input, call with shallow copy:
  innerRecursive([...input], nestedOutput);
  
  function innerRecursive(currArr, parentArr, level){
    const currentLevel = level || 1;
    const currentChildren = [];
    const pointOfNesting = {};
    for (let i of [1,2,3,4]){      
      const item = currArr[i-1];
      //console.log(currentLevel, i, item);
      if (currentLevel == item.level){
        item.id = `${currentLevel}.${i}`;
        item.children = null;
        parentArr.push(item);
        //console.log('output', nestedOutput);
      }
      else {        
        pointOfNesting.id = `${currentLevel}.${i}`;
        pointOfNesting.children = [];
        parentArr.push(pointOfNesting);
        //console.log('parent', parentArr); 
        
        let child = currArr[i-1];
        let j = i - 1;
        let position = 1;
        //console.log(child);

        while (child && child.level > currentLevel){
          //console.log('child', child);
          currentChildren.push(child);
          j +=1;
          child = currArr[j];         
        }        
        currArr.splice(i-1, (j - (i-1) ) );
        currArr.splice(i-1, 0, pointOfNesting);

        innerRecursive([...currentChildren], pointOfNesting.children, currentLevel + 1)
      }      
    }
    
  }  
  return nestedOutput;
}
.as-console-wrapper { max-height: 100% !important; top: 0; }

Output:

[
  {
    "level": 1,
    "x": 0,
    "y": 0,
    "id": "1.1",
    "children": null
  },
  {
    "level": 1,
    "x": 16,
    "y": 0,
    "id": "1.2",
    "children": null
  },
  {
    "level": 1,
    "x": 0,
    "y": 16,
    "id": "1.3",
    "children": null
  },
  {
    "id": "1.4",
    "children": [
      {
        "id": "2.1",
        "children": [
          {
            "level": 3,
            "x": 16,
            "y": 16,
            "id": "3.1",
            "children": null
          },
          {
            "id": "3.2",
            "children": [
              {
                "level": 4,
                "x": 20,
                "y": 16,
                "id": "4.1",
                "children": null
              },
              {
                "id": "4.2",
                "children": [
                  {
                    "level": 5,
                    "x": 22,
                    "y": 16,
                    "id": "5.1",
                    "children": null
                  },
                  {
                    "level": 5,
                    "x": 23,
                    "y": 16,
                    "id": "5.2",
                    "children": null
                  },
                  {
                    "level": 5,
                    "x": 22,
                    "y": 17,
                    "id": "5.3",
                    "children": null
                  },
                  {
                    "level": 5,
                    "x": 23,
                    "y": 17,
                    "id": "5.4",
                    "children": null
                  }
                ]
              },
              {
                "level": 4,
                "x": 20,
                "y": 18,
                "id": "4.3",
                "children": null
              },
              {
                "level": 4,
                "x": 22,
                "y": 18,
                "id": "4.4",
                "children": null
              }
            ]
          },
          {
            "level": 3,
            "x": 16,
            "y": 20,
            "id": "3.3",
            "children": null
          },
          {
            "level": 3,
            "x": 20,
            "y": 20,
            "id": "3.4",
            "children": null
          }
        ]
      },
      {
        "level": 2,
        "x": 24,
        "y": 16,
        "id": "2.2",
        "children": null
      },
      {
        "level": 2,
        "x": 16,
        "y": 24,
        "id": "2.3",
        "children": null
      },
      {
        "level": 2,
        "x": 24,
        "y": 24,
        "id": "2.4",
        "children": null
      }
    ]
  }
]

Corresponding to this quadtree (32 x 32):



来源:https://stackoverflow.com/questions/62196884/javascript-flat-one-dimensional-array-to-tree

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!