Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JS how to reform this irregular object

I have this object which its keys are guaranteed sorted and will be used for the operation. And each of its value is a 2d array.

var obj = {
  "0": [
    [0, 1], [0, 3], [0, 4]
  ],
  "1": [
    [1, 2], [1, 3]
  ],
  "2": [
    [2, 3], [2, 5]
  ],
  "3": [
    [3, 4], [3, 6]
  ],
  "5": [
    [5, 6]
  ],
  "6": [
    [6, 5]
  ]
}

I am trying to concatenate them and for each of its last value of the array is the next index of the object. So, my expected result is an array like this,

The pattern is, I have to find a way from 0 which is the first index of obj, to the last index which is 6 by using the values in each of it and linking its last array value to the next object. If that makes sense.

[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 6]
[0, 1, 2, 5, 6]
[0, 1, 3, 4, 5, 6]
[0, 1, 3, 4]
[0, 1, 3, 6]
[0, 3, 4, 5, 6]
[0, 3, 6]
[0, 4]

This is my code so far, as I don't know how to proceed further..

var result = [];
for (var key in obj) {
    var myarr = obj[key];
    for (var i = 0; i < myarr.length; i++) {
        result.push(myarr[i])
    }
}

Any idea or feedback is welcome.

Edit

One of the expected result was [0, 1, 2, 3, 4, 5, 6], here's the step by step explanation.

  1. The obj key starts from 0 and ends in 6, I have to form a way from 0 to 6 with the arrays in its value.
  2. Starts from obj[0], the first array returns [0, 1], save this to res. (res is now [0, 1])
  3. The last value of array in res is 1, now find the next value in obj[1]
  4. obj[1] has two arrays, and ends with 2 or 3.. So it's possible to append with both of them, so it can be [0, 1, 2] or [0, 1, 3]. In this case, get the first one which is [1, 2] and append the last value to res. (res is now [0, 1, 2]).
  5. The last value of array in res is now 2, now find the next value in obj[2].
  6. obj[2] has two arrays, and ends with 3, or 5.. It's possible to append with both of them, so it can be [0, 1, 2, 3] or [0, 1, 2, 5]. In this case, get the first one which is [2, 3] and append the last value to res. (res is now [0, 1, 2, 3])
  7. The last value of array in res is now 3, now find the next value in obj[3].
  8. Repeat step 4 or 6. (res is now [0, 1, 2, 3, 4]).
  9. The last value of array in res is now 4, now find the next value in obj[4].
  10. Repeat step 4 or 6. (res is now [0, 1, 2, 3, 4, 5]).
  11. The last value of array in res is now 5, now find the next value in obj[5].
  12. Now value 6 is found which should be the end of iteration if you look at the step 4. Repeat step 4 or 6. (res is now [0, 1, 2, 3, 4, 5, 6]).
  13. Repeat from step 1, and form another way to do it, with no duplicates of [0, 1, 2, 3, 4, 5 ,6].
like image 483
Dicky Bullin Avatar asked Oct 27 '16 09:10

Dicky Bullin


People also ask

What should not be declared as an object in JavaScript?

Do Not Declare Strings, Numbers, and Booleans as Objects! When a JavaScript variable is declared with the keyword " new ", the variable is created as an object: Avoid String, Number, and Boolean objects. They complicate your code and slow down execution speed.

How are the properties of an object overwritten in JavaScript?

The properties are overwritten by other objects that have the same properties later in the parameters order. const v1 = 'abc'; const v2 = true; const v3 = 10; const v4 = Symbol('foo'); const obj = Object.assign({}, v1, null, v2, undefined, v3, v4); // Primitives will be wrapped, null and undefined will be ignored.

What is an object in JavaScript?

JavaScript objects are containers for named values called properties or methods. Spaces and line breaks are not important. An object definition can span multiple lines: The name:values pairs in JavaScript objects are called properties: Objects can also have methods.

What is object-oriented programming?

When we write our code using objects to represent entities, that’s called object-oriented programming, in short: “OOP”. OOP is a big thing, an interesting science of its own. How to choose the right entities? How to organize the interaction between them?


2 Answers

This is a proposal, with a single extra output, mentioned below.

[
    [0, 1, 2, 3, 4, 5, 6],
    [0, 1, 2, 3, 6],
    [0, 1, 2, 5, 6],
    [0, 1, 3, 4, 5, 6],     /* extended from below                           */
    [0, 1, 3, 4],           /* original result                               */
    [0, 1, 3, 6],
    [0, 3, 4, 5, 6],        /* extended from below                           */
    [0, 3, 4],              /* extra line, line should not be in result      */
    [0, 3, 6],              /* but follows the same building rule than above */
    [0, 4]
]

Basically this solution is building a tree with the given information about linked nodes.

If some nodes are not contiguous, a backtracking is made for the missing links, with the above function for nodes, checkNodes or with iterPath, to walk the actual collected nodes for missing items.

function getParts(value, path, nodes) {
    function checkNodes(a) {
        if (a[1] === value + 1) {
            getParts(a[1], path.concat(a[1]), nodes);
            return true;
        }
    }

    function iterPath(k) {
        return (object[k] || []).some(function (a) {
            return path[path.length - 1] + 1 === a[1] || iterPath(a[1]);
        });
    }

    value = value || 0;
    path = path || [value];
    nodes = nodes || [];
    if (object[value]) {
        object[value].forEach(function (a, i, aa) {
            if (a[1] === lastKey) {
                parts.push(path.concat(a[1]));
                return;
            }
            getParts(a[1], path.concat(a[1]), nodes.concat(aa.slice(i + 1)));
        });
        return;
    }
    if (nodes.some(checkNodes)) {
        return;
    }
    path.slice(1).some(iterPath) && getParts(path[path.length - 1] + 1, path.concat(path[path.length - 1] + 1), nodes);
    parts.push(path);
}

var object = {
        0: [[0, 1], [0, 3], [0, 4]],
        1: [[1, 2], [1, 3]],
        2: [[2, 3], [2, 5]],
        3: [[3, 4], [3, 6]],
        5: [[5, 6]],
        6: [[6, 5]]
    },
    lastKey = 6,
    parts = [];

getParts();
parts.forEach(function (a) { console.log(JSON.stringify(a)); });
.as-console-wrapper { max-height: 100% !important; top: 0; }
like image 162
Nina Scholz Avatar answered Sep 28 '22 07:09

Nina Scholz


Well, I was sitting on this for some time now, and sharing across my take on the problem:

The input object can be considered as an adjacency list of a tree:

var obj={0:[[0,1],[0,3],[0,4]],1:[[1,2],[1,3]],2:[[2,3],[2,5]],3:[[3,4],[3,6]],5:[[5,6]],6:[[6,5]]};

and the following as the result required, which is in fact, as I see it, the list of all root-to-leaf paths of the tree:

[0,1,2,3,4]
[0,1,2,3,6]
[0,1,2,5,6]
[0,1,3,4]
[0,1,3,6]
[0,3,4]
[0,3,6]
[0,4]

a little different than the result set mentioned in the question which is the below:

[0,1,2,3,4,5,6]
[0,1,2,3,6]
[0,1,2,5,6]
[0,1,3,4,5,6]
[0,1,3,4]
[0,1,3,6]
[0,3,4,5,6]
[0,3,6]
[0,4]

The difference between the results is only the question whether 4 and 6 are leaf nodes

Solution:

So I assume that for our Tree here:

  1. 0 is the root node

  2. 4 and 6 are the leaf nodes

See code below - I created a tree first, and from that listed out all the root to leaf paths:

// removed "6:[[6,5]]" as 6 is a 'leaf' of the tree
var obj={0:[[0,1],[0,3],[0,4]],1:[[1,2],[1,3]],2:[[2,3],[2,5]],3:[[3,4],[3,6]],5:[[5,6]]};

var availableNodes = Object.keys(obj);

var tree = availableNodes.reduce(function(hash) {
  return function(prev, curr) {
    hash[curr] = hash[curr] || {};
    hash[curr].children = hash[curr].children || [];
    obj[curr].forEach(function(element) {
      hash[element[1]] = hash[element[1]] || {};
      hash[element[1]].children = hash[element[1]].children || [];
      hash[curr].rootPath = hash[curr].rootPath || [];
      hash[curr].children.push({value: element[1],children: hash[element[1]].children});
    });
    curr && prev.push({value: curr,children: hash[curr].children});
    return prev;
  };
}(Object.create(null)), []);

//console.log(JSON.stringify(tree));

var result = [];

function rootToLeafPaths(node, path) {
  path.push(+node.value);
  if (node.children.length === 0) {
    result.push(Array.from(path));
    path.pop();
  } else {
    node.children.forEach(function(element) {
      rootToLeafPaths(element, path);
    });
    path.pop();
  }
}

rootToLeafPaths(tree[0], []);
console.log(JSON.stringify(result));
.as-console-wrapper{top:0;max-height:100%!important;}
like image 38
kukkuz Avatar answered Sep 28 '22 07:09

kukkuz