3

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>); 

3 Answers 3

5

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.

Sign up to request clarification or add additional context in comments.

Comments

3

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); 

7 Comments

Yeah, looks like the option, but i want to avoid the case lookup at runtime
What do you mean?
i do not want to perform any if else operations. i've left it as a last option
@Ajeetkumar I'm not sure I understand: how can you check the value of expComponents without a condition?
check my second example of Collections::max or ::min. So that function whenever runs it will directly use .apply, it won't check for min or max because it is already told to it that min or max is to be run. getting the idea?
|
0

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); ... 

1 Comment

Hi, i find your answer interesting but have difficulty understanding it fully. BiFunction parameters are Integer, Integer, Integer ? in case of Integer::max, have you missed myFunction.apply call?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.