I have a list of nodes and their requirements (i.e., ancestors). The good news is, the list is guaranteed to be in "order" (where order means that no node will be on the list until its requirements are also on the list), but I'd like to put it into a "hierarchy", so I can handle nodes at the same level in parallel.
For example, I have
+------+----------------+
| Node | Requires |
+------+----------------+
| A | |
+------+----------------+
| B | |
+------+----------------+
| C | A,B |
+------+----------------+
| D | C |
+------+----------------+
| E | |
+------+----------------+
| F | E |
+------+----------------+
...
and what I want is
+---+----------+
| 0 | A,B,E |
+---+----------+
| 1 | C,F |
+---+----------+
| 2 | D |
+---+----------+
...
I'm getting the data from a 3rd-party library, and the way it comes in is the ordered list of nodes is an array of strings ($nodes
), and the dependencies are stored in another object as an array with a key of the node name ($foreign_obj->reqs[ <node> ]->reqs
).
EDIT: inserted based on comment:
Here's a var_export
of those two items:
nodes:
array ( 0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 5 => 'F', 6 => 'G', 7 => 'H', )
the first few entries from foreign_obj->reqs:
array ( 'A' => _Requirement::__set_state((array( 'name' => 'A', 'src' => '/path/to/A.js', deps => array ( ), )), 'B' => _Requirement::__set_state((array( 'name' => 'B', 'src' => '/path/to/B.js', deps => array ( ), )), 'C' => _Requirement::__set_state((array( 'name' => 'C', 'src' => '/path/to/C.js', deps => array ( 0 => 'A', 1 => 'B', ), )),
...
All of the other questions I can find on here that are similar deal with the situation where you have a known, singular parent (e.g., Flat PHP Array to Hierarchy Tree), or you at least already know the parents (e.g., PHP hierarchical array - Parents and childs). The challenge I have here is that the data is the other direction (i.e., I have the given leafs and their ancestors).
I could use something like graphp/graph, but that seems like overkill. In particular, given that the list is already in order, I'm hoping there's a fairly simple iteration I can do here, and it may not even need to be recursive.
I think something as simple as this would work:
$hierarchy = array();
foreach ( $nodes as $node ) {
$requirements = $foreign_obj->reqs[ $node ]->reqs;
if ( ! is_array( $requirements ) || empty( $requirements ) ) {
array_push($hierarchy[0], $node);
continue;
}
$index = 0;
foreach ($requirements as $req) {
<find req in $hierarchy>
if (<index of heirarchy where found> > $index) {
$index = <index of heirarchy where found>
}
}
array_push( $hierarchy[ $index + 1], $node);
}
The two questions, then, are:
- Does the above look like it would work, logically, or am I missing some edge case?
- What's the most efficient/elegant PHP way to do the
<find req in $hierarchy>
bit?