I'm a bit stumped. I have an array of elements that will be used to calculate current element's value depending on an element that was in a chain before it. (Think of a timeline where element's date is +/- n days relative to some other element.) Problem is, only one element will have initial value [ie start date] and other elements that are before it (prtcxxx series) will subtract from it and then from each other, and elements after it (testxxxx, reportxxxx, issuexxxx) will add to it and then to each other in chain. I tried creating array.sort with rules to allow that kind of sorting, but it's not working. I also tried creating my own sort workflow witth if/elseif -> outputArr.splice, but no luck there either :/
// array columns:
// [elementID, I_depend_on_this_elementID, my_value, calculated_value]
let arrayMe = [
["report0700", "report0500"],
["issue0200", "report1000"],
["report1000", "report0900"],
["report0900", "report0800"],
["issue0230", "report1000"],
["issue0000", ""],
["issue0100", ""],
["issue0110", ""],
["issue0240", "issue0240"],
["test0100", "test0100",10,10], // this element will actually start the chain for everything else
["protc0000", ""],
["protc0300", "protc0500"],
["report0600", "protc0100"],
["report0800", "report0700"],
["issue0120", ""],
["issue0220", ""],
["protc0200", "protc0300"],
["protc0600", "protc0100"],
["protc0100", "protc0200"],
["protc0700", "protc0800"],
["protc0500", "protc0700"],
["protc0400", "protc0500"],
["protc1000", "test0100"],
["protc0900", "protc1000"],
["protc0800", "protc0900"],
["test0000", ""],
["test0400", "test0300"],
["test0300", "test0200"],
["test0200", "test0100"],
["test0600", "test0500"],
["test0700", "test0500"],
["test0500", "test0400"],
["report0000", ""],
["report0400", "report0300"],
["report0500", "report0300"],
["report0300", "report0200"],
["report0200", "report0100"],
["report0100", "test0400"],
];
arrayMe.sort((a, b) => {
console.log(a[0], " -- ", b[1]);
if (a[0] == b[1]) {return 1;} // a before b, because b depends on a
if (a[1] == b[0]) {return -1;} // b before a, because a depends on b
if (a[1] == a[0]) {return 1;} // a in front, because it depends only on itself and others will depend on it
if (a[1] == "") {return 0;} // a can be wherever, because it doesn't depend on anyone, nor anyone will depend on it
return 0;
});
console.log(arrayMe);
And my own sort attempt (I guess it would need several repeats/recursive to finish the sort?):
let ordered = [];
arrayMe.forEach(function (a) {
if (a[0] === a[1] || a[1] === "" || a[1] === null || a[3]) {
ordered.splice(0, 0, a); // element is a seed for others or independedt, put it at front
} else if (ordered.findIndex((x) => x[1] === a[0]) !== -1) { // see if some x already in ordered array already depends on 'a' and then put the a in front of it
let where = ordered.findIndex((x) => x[1] === a[0]) - 1;
ordered.splice(where, 0, a);
} else if (ordered.findIndex((x) => x[1] === a[1]) !== -1) { // see if 'a' depends on some x already in the array and if so, put a behind x
ordered.splice(
ordered.findIndex((x) => x[1] === a[1]) + 1, 0, a
);
} else {
ordered.splice(ordered.length, 0, a);
}
});
None of the array elements cause circular reference.
The above model is simplified, in realyty I'll have a dynamic-ish object with elements like this, where due_date is to be calculated based on other elements:
report0700: {
title: "A task to be performed by specific date, 7 days after report0500",
relative_to: "report0500",
delta: +7,
due_date: null // report0500.due_date = 03 DEC 2020 + delta, -> report0700.due_date = 10 DEC 2020
},
report0800: {
title: "another to be performed by specific date, 14 days after report0700",
relative_to: "report0700",
delta: +14,
due_date: null // report0700.due_date = 10 DEC 2020 + delta, -> report0800.due_date = 24 DEC 2020
},
Any advice would be appreciated.
EDIT:
There are two examples of attempted sorting above:
arrayMe.sort((a, b) => { ...
and
arrayMe.forEach(function (a) { ...
Expected element order after being sorted by how they depend on each other looks like this.
let arrayMe = [
["test0100", "test0100", 10, 10], // this element will actually start the chain for everything else
["issue0240", "issue0240"], // depends on itself, just dump it in front
["issue0000", ""], // does not depend on any other, just dump it anywhere
["issue0100", ""], // does not depend on any other, just dump it anywhere
["issue0110", ""], // does not depend on any other, just dump it anywhere
["protc0000", ""], // does not depend on any other, just dump it anywhere
["issue0120", ""], // does not depend on any other, just dump it anywhere
["issue0220", ""], // does not depend on any other, just dump it anywhere
["test0000", ""], // does not depend on any other, just dump it anywhere
["report0000", ""], // does not depend on any other, just dump it anywhere
// protcxxxx series, starts by depending on [test0100]
// from here on, the rule is simple:
// element with name in [column1] comes after element named in [column2]
["protc1000", "test0100"], // ie ["protc1000", "test0100"] needs to be positioned anywhere after element ["test0100", "test0100", 10, 10]
["protc0900", "protc1000"],
["protc0800", "protc0900"],
["protc0700", "protc0800"],
["protc0500", "protc0700"],
["protc0400", "protc0500"],
["protc0300", "protc0500"],
["protc0200", "protc0300"],
["protc0100", "protc0200"],
["protc0600", "protc0100"],
["report0600", "protc0100"],
// testxxxx series, starts by depending on [test0100] and can be mangled in between protcxxxx nodes
["test0200", "test0100"],
["test0300", "test0200"],
["test0400", "test0300"],
["test0500", "test0400"],
["test0600", "test0500"],
["test0700", "test0500"],
// reportxxxx series, starts by depending on [test0400]
["report0100", "test0400"],
["report0200", "report0100"],
["report0300", "report0200"],
["report0400", "report0300"],
["report0500", "report0300"],
["report0700", "report0500"],
["report0800", "report0700"],
["report0900", "report0800"],
["report1000", "report0900"],
// issuetxxxx series, starts by depending on [report1000]
["issue0200", "report1000"],
["issue0230", "report1000"],
];