I am trying to process an object that has nested lists 2 levels deep. For example my object can be broken down to something like this:
TopLevel: [
MidLevel: [
LowLevel,
LowLevel,
.
.
],
MidLevel: [
LowLevel,
LowLevel,
.
.
]
.
.
]
Essentially TopLevel
contains a list of MidLevel
objects, which in turn each contain a list of LowLevel
objects. At the end of the processing I would like to build SomeObj
for each of the LowLevel
objects. However SomeObj
requires information from TopLevel
, MidLevel
, and LowLevel
.
I have been trying to write code in a more functional style over the last several months so my first thought was to create a higher order function that I could build up over each level in the object. The function looks like this:
Function<MidLevel, Function<LowLevel, SomeObj>> buildObjects(TopLevel topLevel) {
return midLevel ->
lowLevel -> {
return buildSomeObj(topLevel, midLevel, lowLevel);
};
}
I intend to use this function in some way like the following (assume I have utility functions that provide a stream of the lists):
Function<MidLevel, Function<LowLevel, SomeObj>> topBuilder = buildObjects(topLevel);
List<SomeObj> objs = topLevel.streamMid()
.map(topBuilder)
.streamLow()
.map(Function::apply)
.collect(/*collect to list*/);
However, this obviously does not work because once I apply the MidLevel
objects to the topBuilder
function my stream is now a stream of functions and not MidLevel
objects, thus I do not have access to the list of LowLevel
objects in the stream anymore.
Is there any solution to this or am I trying to solve this functionally when it's not well suited to it? Is there a way to both apply the function, and also have access to the original object that was applied to that function?
flatMap()
and nesting are the way to go. Try this:
topLevelStream() //create a stream of top level elements
.flatMap( top -> top.streamMid() //create a stream of mid level elements
.flatMap( mid -> mid.streamLow() //create a stream of low level elements
.map(low -> "use top, mid and low here")
)
)
.collect( ... );
By nesting like this you still have access to the elements in the outer functions and the combination of flatMap()
and map()
exposes the stream that map()
is called upon to collect()
.
You could simply use flatMap
as:
List<SomeObj> objs = topLevel.getMidLevels().stream()
.flatMap(a -> a.getLowLevels().stream().map(b -> topBuilder.apply(a).apply(b)))
.collect(Collectors.toList());
with your entities analogous to:
class TopLevel {
List<MidLevel> midLevels;
}
class MidLevel {
List<LowLevel> lowLevels;
}
class LowLevel {
}
class SomeObj {
}
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