Reputation: 61
I need to take a given record and populate a list with the identifiers of all of its child records ad infinitem (I.e. all child records of original item, all child records of children, all child records of grandchildren etc.) I currently have a method which produces what I want but it's not the most easily read and uses iteration rather than recursion. I'm wondering if there is a cleaner way to achieve what I want, potentially using a recursive call but with the primary aim of making the code easier to read. Current implementation is as follows
public List<String> getAllChildRecords(targetRecord) {
final List<String> allChildRecordIds = new ArrayList<>();
final List<String> recordIdsForQuery = new ArrayList<>();
final List<String> queryResults = new ArrayList<>();
recordIdsForQuery.add(targetRecord);
while (!recordIdsForQuery .isEmpty()) {
for (final String queryParentId : recordIdsForQuery ) {
queryResults.addAll(
[DBAccessLayerClass].[getChildRecordIds](queryParentId));
}
allChildRecordIds .addAll(queryResults);
recordIdsForQuery .clear();
recordIdsForQuery .addAll(queryResults);
queryResults.clear();
}
return allChildRecordIds
}
Upvotes: 0
Views: 94
Reputation: 102832
Recursion isn't usually the right answer, especially in java - it tends to be slow, for example, and produce convoluted stack traces. Therefore, 'just rewrite to recursion' is not the slamdunk answer, and thus, not a slamdunk improvement if you're concerned about readability.
The usual trick is to work with a queue. Also, stop declaring things final 'for readability' - you're adding a ton of noise to this code. If you insist on having 'changing locals' be reduced to a minimum for readability, configure your IDE to render writes to locals in a highly visible manner, don't mess up your code by adding a bunch of noisy keywords everywhere.
var out = new ArrayList<String>();
var queue = new ArrayDeque<String>();
queue.add(targetRecord);
while (!queue.isEmpty()) {
String id = queue.pop();
var childIds = DbAccessLayerClass.getChildRecordIds(id));
out.addAll(childIds);
queue.addAll(childIds);
}
return out;
If you're afraid of loops or repeats (where 1 item can be a child of multiple separate entries, for example), turn your out
into a (Linked)HashSet
instead, and add childIds.removeAll(out);
right after DbAccessLayerClass.getChildRecordIds
.
Upvotes: 1