Reputation: 1329
I have a case as below:
RowDataSet rdsHavingMaxNumericValue = dataList.stream()
.filter(r -> r.getLong(NUMERIC_VALUE) != null)
.max((r1, r2) -> r1.getId().compareTo(r2.getId()))
.get();
I've two cases where I need to find either min or max depending on a case? how can i replace the call max at third line by a Function so that it direcly uses .apply() method and performs the operation?
I'v successfully assigned Collection.max or Collection min as below:
BiFunction<List<RowDataSet>, Comparator<RowDataSet>, RowDataSet> mrOrlrOperation = expComponents[0] == 'M' ? Collections::max : Collections::min;
and i use it as below:
RowDataSet rds = mrOrlrOperation.apply(dataList, <some comparator>);
Upvotes: 3
Views: 240
Reputation: 36401
max
is a reducing operation, then you can use the generic reduce
:
public void reducing(BiOperator<...> myFunction) {
RowDataSet rdsHavingMaxNumericValue = dataList.stream()
.filter(r -> r.getLong(NUMERIC_VALUE) != null)
.reduce((r1, r2) -> myFunction.apply(r1,r2))
.get();
}
...
reducing(Integer::max);
...
Upvotes: 0
Reputation: 298153
The choice to use min
instead of max
is not different to still using the max
operation, but with a reversed order, so you could use
Initialization:
Comparator<RowDataSet> c = Comparator.comparingLong(RowDataSet::getId);
if(expComponents[0] != 'M') c = c.reversed();
Actual operation
RowDataSet rdsHavingMaxNumericValue =
dataList.stream()
.filter(r -> r.getLong(NUMERIC_VALUE) != null)
.max(c)
.get();
Reversing the order has no performance impact. It just implies calling r2.getId().compareTo(r1.getId())
instead of r1.getId().compareTo(r2.getId())
…
An alternative would be
Comparator<RowDataSet> c = Comparator.comparingLong(RowDataSet::getId);
BinaryOperator<RowDataSet> op = expComponents[0] == 'M'?
BinaryOperator.maxBy(c): BinaryOperator.minBy(c);
RowDataSet rdsHavingMaxNumericValue =
dataList.stream()
.filter(r -> r.getLong(NUMERIC_VALUE) != null)
.reduce(op)
.get();
This anticipates what min
and max
would do…
You can use either variant to create your BiFunction
, e.g.
Variant 1:
Function<Comparator<RowDataSet>, Comparator<RowDataSet>>
maxOrMin = expComponents[0] == 'M'? Function.identity(): Comparator::reversed;
BiFunction<List<RowDataSet>, Comparator<RowDataSet>, RowDataSet> mrOrlrOperation
= (dataList, comparator) -> dataList.stream()
.filter(r -> r.getLong(NUMERIC_VALUE) != null)
.max(maxOrMin.apply(comparator))
.get();
Variant 2:
Function<Comparator<RowDataSet>, BinaryOperator<RowDataSet>>
maxOrMin = expComponents[0] == 'M'? BinaryOperator::maxBy: BinaryOperator::minBy;
BiFunction<List<RowDataSet>, Comparator<RowDataSet>, RowDataSet> mrOrlrOperation
= (dataList, comparator) -> dataList.stream()
.filter(r -> r.getLong(NUMERIC_VALUE) != null)
.reduce(maxOrMin.apply(comparator))
.get();
Of course, you could also live with a code duplication
BiFunction<List<RowDataSet>, Comparator<RowDataSet>, RowDataSet> mrOrlrOperation
= expComponents[0] == 'M'?
(dataList, comparator) -> dataList.stream()
.filter(r -> r.getLong(NUMERIC_VALUE) != null)
.max(comparator)
.get():
(dataList, comparator) -> dataList.stream()
.filter(r -> r.getLong(NUMERIC_VALUE) != null)
.min(comparator)
.get();
In either case, the condition expComponents[0] == 'M'
is checked only once when the BiFunction
is created and never evaluated when mrOrlrOperation.apply(…)
is invoked.
Upvotes: 5
Reputation: 328608
It would probably be simpler to just use a condition:
Stream<?> stream = dataList.stream()
.filter(r -> r.getLong(NUMERIC_VALUE) != null);
Comparator<RowDataSet> c = Comparator.comparingLong(RowDataSet::getId);
RowDataSet rdsHavingMaxNumericValue =
expComponents[0] == 'M' ? stream.max(c).get() : stream.min(c).get();
You can store the min/max operation in a separate Function
if you want:
BiFunction<Stream<RowDataSet>, Comparator<RowDataSet>, RowDataSet>> operation =
expComponents[0] == 'M' ? (s, c) -> s.max(c).get() : (s, c) -> s.min(c).get();
RowDataSet rdsHavingMaxNumericValue = operation.apply(stream, c);
Upvotes: 3