Reputation: 907
Let's say I have some numbers in the working memory, and in a rule I need to check that the 3 higher numbers have a property (that they are all odd for example), how would you write that in pure Drools?
I could collect all the numbers in a list and then have a Java function that filters it taking just the best 3 (like order the list and take the last 3) and then check the property on those 3 with Drools, but I wonder if this can be done in pure Drools maybe with an accumulate?
I have tried to think for a bit but couldn't find a solution.
Upvotes: 0
Views: 877
Reputation: 907
As my hint in the question, this can be achieved more elegantly with a custom accumulate function:
rule "odd"
when
accumulate($l : Integer(), $r : reverseSort($l); $r.size > 2, ($r[0] % 2) == 1, ($r[1] % 2) == 1, ($r[2] % 2) == 1)
then
System.out.println("Best 3 are odd numbers: " + $r);
end
and the accumulate function:
package com.test;
import java.io.*;
import java.util.*;
import org.kie.api.runtime.rule.AccumulateFunction;
public class ReverseSortAccumulator implements AccumulateFunction {
private static class accumulatorData implements Serializable {
private static final long serialVersionUID = 1L;
private List<Object> elements = new ArrayList<>();
private List<Object> getElements() {
return elements;
}
public void init() {
getElements().clear();
}
public void add(Object element) {
getElements().add(element);
}
public void remove(Object element) {
getElements().remove(element);
}
public List<Object> reverseSort() {
return getElements().stream()
.sorted(Collections.reverseOrder())
.collect(Collectors.toList());
}
}
@Override
public Serializable createContext() {
return new accumulatorData();
}
@Override
public void init(Serializable context) {
getContextData(context).init();
}
@Override
public void accumulate(Serializable context, Object input) {
getContextData(context).add(input);
}
@Override
public void reverse(Serializable context, Object input) {
getContextData(context).remove(input);
}
@Override
public List<?> getResult(Serializable context) {
return getContextData(context).reverseSort();
}
@Override
public boolean supportsReverse() {
return true;
}
@Override
public Class<?> getResultType() {
return List.class;
}
private accumulatorData getContextData(Serializable context) {
return (accumulatorData) context;
}
@Override
public void writeExternal(ObjectOutput out) {
// no need to externalise data over sessions
}
@Override
public void readExternal(ObjectInput in) {
// no need for externalised data from sessions
}
}
Upvotes: 0
Reputation: 31300
rule best3
when
$o1: Integer( $i1: intValue, intValue % 2 == 0 )
not Integer( intValue > $i1 )
$o2: Integer( this != $o1, $i2: intValue, intValue % 2 == 1 )
not Integer( intValue > $i2 && < $i1 )
Integer( this != $o1 && != $o2, $i3: intValue, intValue % 2 == 1 )
not Integer( intValue > $i3 && < $i2 )
then
System.out.println( $i1 + " > " + $i2 + " > " + $i3 );
end
Upvotes: 2