Making tree from array representation with option to choose root - javascript

I have tree in array like this:
[ {val: 10,index: 0},{val: 20,index: 1},{val: 30,index: 2},{val: 40,index: 5} ]
and i making tree using indexes ( 0 is root) and my result is this:
50
\
20 30
\ /
10
indexes: ( Now i hope understand this :) )
3 4 5 6
\ / \ /
1 2
\ /
0
Now I have problem with getting tree through index from my api
When i attempt tree/0 it is okay, return this tree above but when i attempt tree/1
i only want
20
or tree/2
50
\
30
Is there any alogrithm which help me exclude unnecessary branches? Any ideas?
Best regards

As a flat array without any parent's, you really don't have a tree structure.
But tree structures in Javascript using an Object is very easy.
Below is an example ->
/*
3 4 5 6
\ / \ /
1 2
\ /
0
*/
var tree = {
index: 0,
val: 'Root',
nodes: [
{
index: 1,
val: 'Value 1',
nodes: [
{
index: 3,
val: 'Value 3'
}, {
index: 4,
val: 'Value 4'
}
]
}, {
index: 2,
val: 'Value 2',
nodes: [
{
index: 5,
val: 'Value 5'
}, {
index: 6,
val: 'Value 6'
}
]
}
]
};
function display(s) {
document.write('<div>' + s + '</div>');
}
function find(root, index) {
if (root.index === index) return root;
if (root.nodes) {
for (let l = 0; l < root.nodes.length; l ++) {
let node = root.nodes[l];
if (node.index === index) return node;
node = find(node, index);
if (node) return node;
}
}
return null;
}
function treeSize(tree) {
let size = 0;
if (tree.nodes)
for (let l = 0; l < tree.nodes.length; l ++)
size += treeSize(tree.nodes[l]);
return size + 1;
}
function showTree(name, index) {
let node = find(tree, index);
if (!node) return;
display(name + '-> Size: ' + treeSize(node));
function draw(node, indent) {
display(indent + node.val);
if (node.nodes) {
for (let l = 0; l < node.nodes.length; l ++)
draw(node.nodes[l], indent + '----');
}
}
draw(node, '');
}
showTree('Tree 0', 0);
display(' ');
showTree('Tree 2', 2);

If you define your tree in the following way,
children of index i = 2*i+1 and 2*i+2
then you can perform a depth first search to print the branches resulting from an index until it reaches the leaf, so
DFS(1) -> DFS(3)
you would get 50 and 30
DFS(i) // would call
DFS(2*i+1) and DFS(2*i+2)

Related

Grouping items in groups of 7 and 8 javascript

Code:
const fs = require("fs");
const { parse } = require("csv-parse");
function getSchedule() {
let schedule = [];
fs.createReadStream("./timetable.csv")
.pipe(parse({ delimiter: ",", from_line: 2 }))
.on("data", function (row) {
let classp = "ΘΗΨ3β";
// Get all items for the students classes and put them in a variable
for (let i = 0; i < row.length; i++) {
if (row[i].includes(classp) || row[i].includes("ΓΘ2Φ5-3") || row[i].includes("ΓΘ1Μ7-3")) {
schedule.push({ number: i, text: row[i] });
}
}
// Filtering to put the items in order
for (let i = 0; i < schedule.length; i++) {
if (schedule[i + 1]) {
if (schedule[i].number > schedule[i + 1].number) {
let temp = schedule[i];
schedule[i] = schedule[i + 1];
schedule[i + 1] = temp;
}
}
}
let numberOfObjects = 8 // <-- decides number of objects in each group
// Group items from schedule into groups of 8
let groupedProducts = schedule.reduce((acc, elem, index) => {
let rowNum = Math.floor(index / numberOfObjects) + 1;
acc[`${rowNum}`] = acc[`${rowNum}`] || [];
acc[`${rowNum}`].push(elem);
return acc
}, {});
console.log(groupedProducts)
});
}
getSchedule();
Output:
{
'1': [
{ number: 3, text: 'ΓΘ1Μ7-3 / 16 / Μαθηματικά Εμβ. 4-ωρ 04ΓΘΚ' },
{ number: 4, text: 'ΘΗΨ3β / 24 / Ψηφ.Ηλεκτρονικά II Γ ΘΗΥ' },
{ number: 5, text: 'ΘΗΨ3β / 24 / Ψηφ.Ηλεκτρονικά II Γ ΘΗΥ' },
{ number: 6, text: 'ΓΘ2Φ5-3 / 53 / Φυσική ΘΓΚ3-Μ6' },
{ number: 7, text: 'ΘΗΨ3β / 11 / Νέα Ελληνικά ΘΓΚ3-Μ1 Γ' },
{ number: 8, text: 'ΘΗΨ3β / 11 / Νέα Ελληνικά ΘΓΚ3-Μ1 Γ' },
{ number: 9, text: 'ΘΗΨ3β / 138α / Θρησκευτικά ΘΓΚ3-Μ1 Γ' },
{
number: 10,
text: 'ΘΗΨ3β / 118 / Εφαρμ.Προγραμ. ΙΙΙ Γ ΘΗΨ'
}
],
.....
'5': [
{ number: 37, text: 'ΓΘ1Μ7-3 / 16 / Μαθηματικά Εμβ. 4-ωρ 04ΓΘΚ' },
{
number: 39,
text: 'ΘΗΨ3β / 112 / Μικροελ. Ρομποτική Γ ΘΗΨ'
},
{
number: 40,
text: 'ΘΗΨ3β / 118 / Εφαρμ.Προγραμ. ΙΙΙ Γ ΘΗΨ'
},
{
number: 41,
text: 'ΘΗΨ3β / 118 / Εφαρμ.Προγραμ. ΙΙΙ Γ ΘΗΨ'
}
]
}
Basically what I want is to have 8 elements in the first one and 4th one and 7 in the 2nd 3rd and 5th but currently it adds 8 in all of them and 3 or 4 in the last. I tried multiple solutions like if statements and forcing an empty element in between the last and first of each element but I didn't seem to succeed.
const fs = require("fs");
const { parse } = require("csv-parse");
function getSchedule() {
let schedule = [];
fs.createReadStream("./timetable.csv")
.pipe(parse({ delimiter: ",", from_line: 2 }))
.on("data", function (row) {
let classp = "ΘΗΨ3β";
// Get all items for the students classes and put them in a variable
for (let i = 0; i < row.length; i++) {
if (row[i].includes(classp) || row[i].includes("ΓΘ2Φ5-3") || row[i].includes("ΓΘ1Μ7-3") || row[i].includes("ΓΘ2Φ1-3")) {
schedule.push({ number: i, text: row[i] });
}
}
// Filtering to put the items in order
for (let i = 0; i < schedule.length; i++) {
if (schedule[i + 1]) {
if (schedule[i].number > schedule[i + 1].number) {
let temp = schedule[i];
schedule[i] = schedule[i + 1];
schedule[i + 1] = temp;
}
}
}
// Group items from schedule into groups of 8
let groupSizes = [8, 7, 7, 8, 7];
let start = 0;
let result = [];
for (let size of groupSizes) {
result.push(schedule.slice(start, start + size));
start += size;
}
console.log(result)
});
}
getSchedule();

d3 js: creating a nested array (matrix) from a flat array

I have an array of objects nodes, where each component object has .id property, and I would like to create a square matrix which is a nested array indexed by [id][id] representing node-by-node interactions:
nodes.forEach(function(node, i) {
matrix[node.id] = nodes.forEach(
function(node1, j) {
console.log(i,j);
return {
"x": j,
"y": i,
"z": 0
};
});
console.log(i, matrix[node.id]);
});
In the console I am getting:
...
149 1
...
149 148
149 149
149 undefined
Why is the object is not assigned in the expression matrix[node.id] = ...? Why there is no error or warning? How can I fix it?
Upd: following #pilotcam explanation that forEach does not return a value, I tried following:
var matrix = [];
var testnodes = [{id: "aaa", a:10},
{id: "aab", a:20},
{id: "aac", a:30},
{id: "aba", a:40}]
testnodes.forEach(function(node, i) {
matrix[node.id] = [];
// [{x: 1, y:2, z:0}, {x:2,y:3,z:0}];
testnodes.forEach(
function(node1, j) {
matrix[node.id][node1.id] = {
x: j,
y: i,
z: 0
};
console.log(i,j, node.id, node1.id, matrix[node.id][node1.id]);
});
console.log(i, matrix[node.id]);
});
Still my matrix is not getting filled in the inner loop:
...
3 1 aba aab Object { x: 1, y: 3, z: 0 }
3 2 aba aac Object { x: 2, y: 3, z: 0 }
3 3 aba aba Object { x: 3, y: 3, z: 0 }
3 Array [ ]
The javascript forEach method does not return a value. You probably want to do
matrix[node.id] = [];
...and manipulate that inside the second forEach. From the question posed, I'm guessing you want something like this:
nodes.forEach(function(node, i) {
matrix[node.id] = [];
nodes.forEach(
function(node1, j) {
console.log(i,j);
matrix[node.id][node1.id] = {
"x": j,
"y": i,
"z": 0
};
});
console.log(i, matrix[node.id]);
});
I modified the fiddle to loop through your hash table and show that it is probably doing what you want. https://jsfiddle.net/rtxbzove/
The issue is that I try to index an array with non-integer values. The proper way seems to use an 'object' / hash table:
var matrix = {};
var testnodes = [{id: "aaa", a:10},
{id: "aab", a:20},
{id: "aac", a:30},
{id: "aba", a:40}]
// with simple for loops:
for (var i = 0, len = testnodes.length; i < len; i++) {
matrix[testnodes[i].id] = {};
for (var j = 0, len = testnodes.length; j < len; j++) {
matrix[testnodes[i].id][testnodes[j].id] = {
x: j,
y: i,
z: 0
};
}
console.log( "matrix:", matrix[testnodes[i].id] );
}
console.log( "matrix:", matrix);
Alternatively, with forEach loops:
testnodes.forEach(function(node, i) {
matrix[node.id] = {};
testnodes.forEach(
function(node1, j) {
console.log(i,j);
matrix[node.id][node1.id] = {
"x": j,
"y": i,
"z": 0
};
});
console.log(i, matrix[node.id]);
});

javascript compare two array find difference

I have two array, could be integer array, string array or even object array, for demo purpose, I'll use integer array.
array1: array2:
0 99
1 1
101 5
2 100
100 97
5 101
4 4
I want to have a function return the array include all the information about the difference between two arrays.
result would be:
0 -- {match:false,leftIndex:0 }
-- 99 {match:false: rightIndex:0}
1 1 {match:true: leftIndex:1,rightIndex:1}
-- 5 {match:false: rightIndex:2}
-- 100 {match:false: rightIndex:3}
-- 97 {match:false: rightIndex:4}
101 101 {match:false:leftIndex:2,rightIndex:5}
2 -- {match:false:leftIndex:3 }
100 -- {match:false:leftIndex:4 }
5 -- {match:false:leftIndex:5 }
4 4 {match:false:leftIndex:6,rightIndex:6}
What is the best way to approach this?
I'm planning to use this function to display a side by side view for those two array using angularJS directive method. will that work?
I suggest to use a Map for the values as key and indices as values for the matched check, if the delta of rightIndexand leftIndex is smaller than zero.
On this case, a matched item is found and if some other values from the right side are missing, they are picket up.
For the last part, possible leftover of array2 is pushed, too.
0 1 2 4 5 97 99 100 101 values
0 1 3 6 5 - - 4 2 leftIndex
- 1 - 6 2 4 0 3 5 rightIndex
- 0 - 0 -3 - - -1 3 delta: p2 - p1
* * * relevant only delta >= 0
var array1 = [0, 1, 101, 2, 100, 5, 4],
array2 = [ 99, 1, 5, 100, 97, 101, 4],
map = new Map,
j = 0,
result = [];
array2.forEach(map.set.bind(map));
array1.forEach(function (a, i) {
if (map.has(a) && map.get(a) >= i) {
while (j < map.get(a)) {
result.push({ value: array2[j], match: false, rightIndex: j });
j++;
}
result.push({ value: a, match: true, leftIndex: i, rightIndex: j });
j++;
return;
}
result.push({ value: a, match: false, leftIndex: i });
});
while (j < array2.length) {
result.push({ value: array2[j], match: false, rightIndex: j });
j++;
}
console.log(result);
If you can use last ES6 features I'll go with something like this:
function areArrayEqual(array1, array2) {
// Based on http://stackoverflow.com/a/14853974/2586392
if (array1.length !== array2.length) return false;
for (var i = 0, l=array1.length; i < l; i++) {
if (!areArrayEqual(array1[i], array2[i]) return false;
else if (array1[i] != array2[i]) return false;
}
return true;
})
var result = [];
array1.forEach((value, i) => {
let j = array2.findIndex(x => {
if (typeof value !== typeof x) return false;
if (typeof value === 'object') return areArrayEquals(Object.values(x), Object.values(value));
if (typeof value === 'array') return areArrayEquals(x, value);
return x === value;
});
result.push([value, j === -1 ? '---' : value , {
match: !!(j + 1),
leftIndex: i,
rightIndex: j === -1 ? '---' : j
}]);
if (j !== -1) {
delete array2[j];
}
});
array2.forEach((value, i) => {
result.push(['---', value, {match: false, leftIndex: '---', rightIndex: i}]);
});
Otherwise you can still use something similar, but you need to polyfill Object.values and maybe forEach as well

Parsing this table with Javascript into array of objects

I have this source table data:
And I would like to get data parsed like this (grouped by row):
I grouped source table into an array of objects.
This is my array:
[ { rowId: 4, colId: 10 } { rowId: 4, colId: 11 } .... ]
Now I would like to get an array of parsed objects..
How can I do this?
I parsed the array with a for loop but I got some error when I create the new array of objects..
My code:
for (var i=0; i<tableArray.length; i++) {
if (tableArray[i].rowId != rowLast) {
bar = true;
var row = tableArray[i].rowId;
var start = tableArray[i].colId;
}
if ((bar)&&(tableArray[i].colId != colLast)) {
var end = tableArray[i].colId;
tab = { row: row, start: start, end: end }
newTableArray.push(tab);
bar = false;
}
rowLast = tableArray[i].rowId;
colLast = tableArray[i].colId;
}
Help! I'm a bit confused in loop :(
Many thanks.
You could group the elements and use an object for the last values. This solution needs sorted data.
var array = [{ rowId: 4, colId: 10 }, { rowId: 4, colId: 11 }, { rowId: 4, colId: 12 }, { rowId: 4, colId: 20 }, { rowId: 4, colId: 21 }, { rowId: 6, colId: 6 }, { rowId: 6, colId: 7 }, { rowId: 6, colId: 8 }, { rowId: 7, colId: 12 }, ],
group = [];
array.forEach(function (a, i) {
if (!i || // group changes if first object i = 0
this.last.row !== a.rowId || // or different rowId
this.last.end + 1 !== a.colId // or not in sequence
) {
this.last = { row: a.rowId, start: a.colId, end: a.colId };
group.push(this.last);
}
this.last.end = a.colId;
}, {});
console.log(group);
I would rather write a function to generate the new array, I hope the comments explain the thought process behind it:
function transform(array) {
var output = [];
// initiates the first object you want in your output array
// with the row and colId of the first object from the input array
var obj = {
row: array[0].row,
start: array[0].colId,
end: array[0].colId
};
// Loop starts at 1 instead of 0 because we used the first object array[0] already
for (var i = 1; i < array.length; i++) {
var current = array[i];
// if the current objects row is still the same,
// AND the colId is the next colId (meaning no spare cols between)
// set the new objects end to this colId
if(obj.row === current.row && (current.colId - obj.end) === 1 ){
obj.end = current.colId;
}
// when the row does not match, add the object to the output array and
// re-innitiate it with the current objects row and colId
else {
output.push(obj);
obj.row = current.row;
obj.start = current.colId;
obj.end = current.colId;
}
}
// Once the loop is done, add the last remaining object to the output array
output.push(obj);
return output;
}

Finding the middle index between any two indexes in a circular array

I have an array and three indexes:
var arr = ['a', 'b', 'c', 'd'];
var f = 0; // first element
var l = arr.length - 1; // last element
var c = 0; // current element
I'm trying to write a function that makes the index c to cycle through the array. The requirement is for it to never reach the index l. So, whenever c reaches a certain value, f and l need to be increased as well.
A reasonable value to work as a limit for c I thought would be the middle point between f and l. The function I wrote is this:
var mod = function(x, m) {
var r = x%m;
return r<0 ? r+m : r;
}
while (true) {
console.log('f', f, 'l', l, 'c', c);
if (c == l) {
console.log('error');
}
c = mod(c + 1, arr.length);
if (c > mod(l - f, arr.length) / 2) {
f = mod(f + 1, arr.length);
l = mod(l + 1, arr.length);
}
}
It doesn't work, clearly. Is there a nice simple formula to with the modulo operator to get what I want or the approach is totally wrong?
Here's a fiddle to try it: https://jsfiddle.net/wku37h9e/2/
Edit:
Explaining the purpose of this would be a bit long. Let's just say that in the array are stored the positions of external elements which I have to constantly move around. When the c is close to the l, I advance all the indexes. Graphically would be like this:
1. [f|c] [ ] [ ] [ l ]
2. [ f ] [ c ] [ ] [ l ]
3. [ l ] [ f ] [ c ] [ ] // here I start moving things around
4. [ ] [ l ] [ f ] [ c ]
5. [ c ] [ ] [ l ] [ f ]
6. [ f ] [ c ] [ ] [ l ]
And so on. With more elements in the array there would be more distance between the indexes.
I also use a different than normal version of mod to take in account negative numbers.
I hope it's a bit clearer now
A reasonable value to work as a limit for c I thought would be the middle point between f and l
Finding the mean average between two values, low and high, in mod len
function midPoint(low, high, len) {
var mid;
low %= len;
high %= len;
while (low < 0) low += len; // these two lines are the
while (high < low) high += len; // most important for direction
mid = (low + high) / 2; // mean average
mid %= len; // convert back to our mod
return mid;
}
So have
// works as expected beyond range of mod
midPoint( 1, -1, 9); // middle of 1..8 (mod 9) = 4.5
midPoint(-7, 5, 9); // middle of 2..5 (mod 9) = 3.5
midPoint(-6, 12, 9); // middle of 3..3 (mod 9) = 3
// and
midPoint( 2, 5, 9); // middle of 2..5 (mod 9) = 3.5
midPoint( 5, 2, 9); // middle of 5..2 (mod 9) = 8 (we went the other way around)
You don't actually have to force the mod until after the whole calculation, so if you really wanted you could do the following, but you lose direction around the loop
function midPoint(A, B, len) {
var mid;
mid = (A + B) / 2; // mean average
mid %= len; // convert back to our mod
while (mid < 0) mid += len; // always positive
return mid;
}
Notice here, however
midPoint(-6, 3, 9); // middle of 3..3 (mod 9) = 7.5
midPoint( 3, 3 + 0 * 9, 9); // middle of 3..3 (mod 9) = 3
midPoint( 3, 3 + 1 * 9, 9); // middle of 3..3 (mod 9) = 7.5
midPoint( 3, 3 + 2 * 9, 9); // middle of 3..3 (mod 9) = 3
i.e. the mid point of 3..3 (mod 9) is both 3 and 7.5, which is true, but which way around we've gone now depends on k (where B - A = k * len + a)
I'm not sure I understand - when I define the mod function that all works:
function test() {
var i=0;
var arr = ['a', 'b', 'c', 'd'];
var f = 0; // first element
var l = arr.length - 1; // last element
var c = 0; // current element
while (true && i < 1000) {
++i;
console.log('f', f, 'l', l, 'c', c);
if (c == l) {
console.log('error');
break;
}
c = mod(c + 1, arr.length);
if (c > mod(l - f, arr.length) / 2) {
f = mod(f + 1, arr.length);
l = mod(l + 1, arr.length);
}
}
}
function mod(a,b) { return a % b;}
Seems to loop c through the possible values, and c is never the same as the (continuously recalculated) value of l... but I don't understand the arithmetic you're trying to apply to f and l there
I calculate only l with the half of the array length plus c. f is then the next index. All numbers are positve.
c f l
1. [ c ] [ ] [ l ] [ f ] 0 3 2 l = length / 2 + c, f = l + 1 both mod length
2. [ f ] [ c ] [ ] [ l ] 1 0 3
3. [ l ] [ f ] [ c ] [ ] 2 1 0
4. [ ] [ l ] [ f ] [ c ] 3 2 1
5. [ c ] [ ] [ l ] [ f ] 0 3 2
6. [ f ] [ c ] [ ] [ l ] 1 0 3
var arr = ['a', 'b', 'c', 'd'],
c, f, l;
for (c = 0; c < arr.length; c++) {
l = (arr.length / 2 + c) % arr.length;
f = (l + 1) % arr.length;
document.write('c:' + c + ' f: ' + f + ' l: ' + l + '<br>');
}

Categories

Resources