Algorithm 如何在Drools中获得列表的所有可能组合?

Algorithm 如何在Drools中获得列表的所有可能组合?,algorithm,drools,Algorithm,Drools,我有一个可变大小的列表,我想得到所有可能的组合。给定一个带有{“a”、“B”、“C”}的列表,我正在寻找以下输出(以任何顺序): 就像 我可以轻松获得预定义数字的所有排列,如下所示: rule "Permutation of 3 List" extends "My List" when $obj1: MyClass() from $myList $obj2: MyClass() from $myList $obj3: MyClass() from $myList then

我有一个可变大小的列表,我想得到所有可能的组合。给定一个带有{“a”、“B”、“C”}的列表,我正在寻找以下输出(以任何顺序):

就像

我可以轻松获得预定义数字的所有排列,如下所示:

rule "Permutation of 3 List" extends "My List"
when
    $obj1: MyClass() from $myList
    $obj2: MyClass() from $myList
    $obj3: MyClass() from $myList
then
    List<MyClass> list = new ArrayList<MyClass>();
    list.add($obj1);
    list.add($obj2);
    list.add($obj3);
    insert(list);
规则“3个列表的排列”扩展了“我的列表”
什么时候
$obj1:MyClass()来自$myList
$obj2:MyClass()来自$myList
$obj3:MyClass()来自$myList
然后
列表=新的ArrayList();
添加($obj1);
增加($obj2);
增加($obj3);
插入(清单);
结束

我不确定如何得到一个变量的排列,这可能没有帮助,因为我需要组合,但如果我能得到大小为k的n个元素的所有排列,我可以运行大小为1到n的n个元素的所有排列,然后从这些排列中取不同的值。但是,我还需要相对高效的方法,并且不要让包含20个元素的列表使服务器崩溃

编辑:修复js应答链接

编辑:删除添加的答案并作为答案发布假设您有一组n个元素s={“a”、“B”、“C”、…}。然后可以构造一个大小为n的数组X,其中X[i]表示第i个元素是否在排列中

例如:S={“A”、“B”、“C”}并以X=[0,0,0]开头

  • X=[0,0,1]表示“C”
  • X=[0,1,0]表示“B”
  • X=[0,1,1]表示“BC”
  • X=[1,0,0]表示“A”
  • X=[1,0,1]表示“AC”
  • X=[1,1,0]表示“AB”
  • X=[1,1,1]表示“ABC”
现在,对于X与多个“1”的每个组合,您可以使用当前算法查找所有排列


也就是说:对于X=[1,1,0]你必须输出“AB”和“BA”,但是对于X=[1,1,1]你必须输出“ABC”、“ACB”、“BCA”、“BAC”、“CBA”和“CAB”。

我想出了一种可能效率不高但有效的方法

我做的第一件事是创建一个名为
Data
的简单Java类来包含字符串的初始列表(我不喜欢JDK类作为事实)

然后,我创建了一个规则,为初始
数据
创建所有可能的排列(使用可变元素)

rule "Permutations"
when
    $d: Data()
    $obj1: String() from $d.getList() do[one]
    $obj2: String(this != $obj1) from $d.getList() do[two]
    $obj3: String((this != $obj1 && this != $obj2)) from $d.getList()
then
    List<String> list = Arrays.asList($obj1, $obj2, $obj3);
    insert(new Permutation(list));
then[one]
    List<String> list = Arrays.asList($obj1);
    insert(new Permutation(list));
then[two]
    List<String> list = Arrays.asList($obj1, $obj2);
    insert(new Permutation(list));
end
就这样!为了从您的Java应用程序中获取会话中剩余的排列,我使用了一个查询:

query getPermutations()
    Permutation($p: elements)
end
我用来测试这一点的Java代码是:

List<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");

        Data data = new Data();
        data.setList(list);

        ksession.insert(data);
        ksession.fireAllRules();

        QueryResults results = ksession.getQueryResults("getPermutations");
        for (QueryResultsRow row : results) {
            List<String> permutation = (List<String>)row.get("$p");

            String m = "Permutation: {"+permutation.stream().collect(Collectors.joining(","))+"}";
            System.out.println(m);
        }
List List=new ArrayList();
列表。添加(“A”);
列表。添加(“B”);
列表。添加(“C”);
数据=新数据();
数据集列表(列表);
K段.插入(数据);
ksession.fireAllRules();
QueryResults results=ksession.getQueryResults(“getPermutations”);
对于(QueryResultsRow行:结果){
列表置换=(列表)行。获取($p);
String m=“排列:{”+Permutation.stream().collect(collector.joining(“,”)+“}”;
系统输出打印项次(m);
}

希望能有所帮助,

我想出了一种方法,可以在Drools中获得n个项目列表的所有组合,但我不会说这是Drools方法。下面是我的规则,它获取我的列表并从列表中获取所有组合:

    rule "Combinations of List" extends "My List"
salience 100
when
then
    //bit shift left j places, equivalent to Math.pow(2,j);
    int max = 1 << $myList.size();
    for(int i = 1; i < max; i++){
        insert(new ComboNumber(i));
    }
end
规则“列表组合”扩展了“我的列表”
突出100
什么时候
然后
//位左移j位,相当于Math.pow(2,j);
int max=1>位)&1)==1){
//获取与位位置关联的obj
add($myList.get(bit));
}
}
插入(新组合(组合列表));
结束
这种方法很有效,但是…性能不太好。毕竟是O(2^n)。我相信得到所有的排列是O(n^n),所以可能会更糟。包含17项或更少项的列表为次秒,但20项需要23秒(即1048576个组合)


如果你能想出一个更好的办法,请让我知道。在C#中直接运行它(在我的同一台机器上)大约快了23倍(单线程)或46倍(并行),每秒成功地迭代了大约2m个组合。

作为一种算法,这很好-但问题需要Drools中的解决方案。这是一个很好的观点,我可以使用布尔值作为索引,添加一个包含false和true的列表,然后如下所示:
当$boolsList1:list(大小>0)$bool1:Boolean()来自$boolsList1$bool2:Boolean()来自$boolsList1$bool3:Boolean()来自$boolsList1
时,获取所有索引组合,但是我仍然需要能够得到一个可变数量的排列来让这对我有效。要清楚的是,这个规则会给我一次规则的“真、真、假”,对应于没有C的{“a”,“B”}(或从右到左)。这允许我获得所有的组合(在这个规则中,一次一个列表),所以这是一个明确的进展。这确实有很大的帮助,因为我对drools和Java相当陌生,但这只适用于列表大小为3的情况,对吗?我需要这个来处理可变大小的列表。如果我们有“A”、“B”、“C”和“D”怎么办?是的,这只适用于大小为3的列表。我在这里做了最初的工作,现在轮到你改进了!;)
rule "Trim duplicated Permutations"
when
    $p1: Permutation()
    $p2: Permutation(
        this != $p1, 
        elements.size == $p1.elements.size,
        elements.containsAll($p1.elements)
    )
then
    retract($p2);
end
query getPermutations()
    Permutation($p: elements)
end
List<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");

        Data data = new Data();
        data.setList(list);

        ksession.insert(data);
        ksession.fireAllRules();

        QueryResults results = ksession.getQueryResults("getPermutations");
        for (QueryResultsRow row : results) {
            List<String> permutation = (List<String>)row.get("$p");

            String m = "Permutation: {"+permutation.stream().collect(Collectors.joining(","))+"}";
            System.out.println(m);
        }
    rule "Combinations of List" extends "My List"
salience 100
when
then
    //bit shift left j places, equivalent to Math.pow(2,j);
    int max = 1 << $myList.size();
    for(int i = 1; i < max; i++){
        insert(new ComboNumber(i));
    }
end
rule "Construct Combination From Bits" extends "My List"
salience 100
when
    $list: List()
    ComboNumber($number: number) from $list
then
    List comboList = new ArrayList();
    for (int bit = 0; bit < $myList.size(); bit++)
{
    //if current bit position is flipped on
    //bitshift right of 0b001101 2 places is 0b0011
    //logical AND of (0b0011 and 0b0001) = 0b0001 (or decimal 1)
    if((($number >> bit) & 1) == 1){
        //get obj associated with bit position
        comboList.add($myList.get(bit));
    }
}
    insert(new Combinations(comboList));
end