在 Drools 的集合中找到最好的 3 个元素
Finding the best 3 elements in a collection in Drools
假设我的工作记忆中有一些数字,并且在规则中我需要检查 3 个更高的数字是否有一个 属性(例如它们都是奇数),你会怎么写在纯 Drools 中?
我可以收集列表中的所有数字,然后有一个 Java 函数过滤它,只取最好的 3 个(比如排序列表并取最后 3 个),然后检查 属性 使用 Drools 的那 3 个,但我想知道这是否可以在纯 Drools 中完成,也许可以通过积累来完成?
想了想也没找到解决办法
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
正如我在问题中的暗示,这可以通过自定义累积函数更优雅地实现:
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
和累加函数:
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
}
}
假设我的工作记忆中有一些数字,并且在规则中我需要检查 3 个更高的数字是否有一个 属性(例如它们都是奇数),你会怎么写在纯 Drools 中?
我可以收集列表中的所有数字,然后有一个 Java 函数过滤它,只取最好的 3 个(比如排序列表并取最后 3 个),然后检查 属性 使用 Drools 的那 3 个,但我想知道这是否可以在纯 Drools 中完成,也许可以通过积累来完成?
想了想也没找到解决办法
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
正如我在问题中的暗示,这可以通过自定义累积函数更优雅地实现:
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
和累加函数:
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
}
}