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.
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.obj[0]
, the first array returns [0, 1]
, save this to res
. (res
is now [0, 1]
)res
is 1
, now find the next value in obj[1]
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]
).res
is now 2
, now find the next value in obj[2]
.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]
)res
is now 3
, now find the next value in obj[3]
.res
is now [0, 1, 2, 3, 4]
).res
is now 4
, now find the next value in obj[4]
.res
is now [0, 1, 2, 3, 4, 5]
).res
is now 5
, now find the next value in obj[5]
.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]
).[0, 1, 2, 3, 4, 5 ,6]
.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.
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.
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.
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?
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; }
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:
0 is the root node
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;}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With