call method
Generates a new hierarchy from the specified tabular data.
final root = stratify(data);
Implementation
HierarchyNode<T?> call(Iterable<T> data) {
var data0 = <Object?>[...data],
nodes = <HierarchyNode<Object?>>[],
nodeByKey = <String, HierarchyNode<Object?>>{};
Function? currentId = id, currentParentId = parentId;
int i, n;
Object? d;
HierarchyNode<Object?>? root;
HierarchyNode<Object?>? parent;
HierarchyNode<Object?> node;
Object? nodeId;
String nodeKey;
if (path != null) {
i = 0;
final I = data.map((d) => normalize(path!(d, i++, data))).toList();
final P = I.map(parentof).toList();
final S = I.toSet()..add("");
i = 0;
String pi;
while (i < P.length) {
pi = P[i];
if (!S.contains(pi)) {
S.add(pi);
I.add(pi);
P.add(parentof(pi));
data0.add(imputed);
}
i++;
}
currentId = (_, i, __) => I[i];
currentParentId = (_, i, __) => P[i];
}
i = 0;
n = data0.length;
for (; i < n; ++i) {
d = data0[i];
nodes.add(node = HierarchyNode(d));
//if (d == imputed) continue;
if ((nodeId = currentId?.call(d, i, data)?.toString()) != null &&
(nodeId as String).isNotEmpty) {
nodeKey = node.id = nodeId;
nodeByKey[nodeKey] = nodeByKey.containsKey(nodeKey) ? ambiguous : node;
}
if ((nodeId = currentParentId?.call(d, i, data)?.toString()) != null &&
(nodeId as String).isNotEmpty) {
node.parentId = nodeId;
}
}
for (i = 0; i < n; ++i) {
node = nodes[i];
if ((nodeId = node.parentId) != null) {
parent = nodeByKey[nodeId];
if (parent == null) throw ArgumentError("missing: $nodeId");
if (parent == ambiguous) throw ArgumentError("ambiguous: $nodeId");
if (parent.children != null) {
parent.children!.add(node);
} else {
parent.children = [node];
}
node.parent = parent;
} else {
if (root != null) throw ArgumentError("multiple roots");
root = node;
}
}
if (root == null) throw ArgumentError("no root");
// When imputing internal nodes, only introduce roots if needed.
// Then replace the imputed marker data with null.
if (path != null) {
while (root!.data == imputed && root.children!.length == 1) {
root = root.children![0];
--n;
}
for (var i = nodes.length - 1; i >= 0; --i) {
node = nodes[i];
if (node.data != imputed) break;
node.data = null;
}
}
root.parent = preroot;
(root
..eachBefore((node, _, __, [___]) {
node.depth = node.parent!.depth + 1;
--n;
}))
.eachBefore(computeHeight);
root.parent = null;
if (n > 0) throw ArgumentError("cycle");
return cast<Object?, T?>(root);
}