I iterate through a tree structure to collect the paths of the leaf nodes. Which way do you prefer to collect the result of the operation:
a) merge the results of the children and return this
private Collection<String> extractPaths(final Element element, final IPath parentPath) {
final IPath path = parentPath.append(element.getLabel());
final Collection<Element> children = getElementChildren(element);
if (children.isEmpty())
return Collections.singletonList(path.toString());
final Set<String> result = new TreeSet<String>();
for (final Element child : children)
result.addAll(extractPaths(child, path));
return result;
}
b) provide the result collection as a parameter and add new elements in each recursion step
private void extractPaths(final Element element, final IPath parentPath, final Set<String> result) {
final IPath path = parentPath.append(element.getLabel());
final Collection<Element> children = getElementChildren(element);
if (children.isEmpty())
result.add(path.toString());
for (final Element child : children)
extractPaths(child, path, result);
}
Both can be used without any problems. Though, former solution is more clean since it doesn't change input parameters. No side effects is in the nature of functional programming.
I assume the latter is meant to call extractPaths(child, path, result)
?
The latter form will be more efficient, as it doesn't need to copy items at every level of recursion. As Boris says, it's less functionally clean - but Java doesn't really provide immutable collections with appropriate methods to create new collections based on them efficiently.
In terms of making it pleasant to call, you could provide a wrapper in the style of the first option which just creates a new set and calls the second option. That's probably what I'd do:
private Collection<String> extractPaths(Element element, IPath parentPath) {
Set<String> ret = new HashSet<String>();
extractPaths(element, parentPath, ret);
return ret;
}
Another alternative is to change the third parameter from a Set<String>
to some sort of "collector" interface: you tell it that you've found a result, without specifying what to do with it. Indeed, the collector could return a new collector to use from then on - leaving it up to the implementation to decide whether to make a functionally-clean "create a new set" version, or hide side-effects in the collector which would just return itself again for reuse.
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