找到没有排列的所有可能的数组组合

时间:2015-04-09 08:10:25

标签: sql arrays postgresql combinations permutation

输入是一个'n'长度的数组 我需要将此数组中的所有组合存储到新数组中。

IN: j='{A, B, C ..}'
OUT: k='{A, B, C, AB, AC, BC, ABC ..}' 

没有重复,所以没有BACA

2 个答案:

答案 0 :(得分:2)

使用recursive CTE

的通用解决方案

适用于支持>运算符的任意数量的元素任何基本数据类型

WITH RECURSIVE t(i) AS (SELECT * FROM unnest('{A,B,C}'::text[]))  -- provide array
, cte AS (
   SELECT i::text AS combo, i, 1 AS ct
   FROM   t

   UNION  ALL
   SELECT cte.combo || t.i::text, t.i, ct + 1
   FROM   cte
   JOIN   t ON t.i > cte.i
   )
SELECT ARRAY (   
   SELECT combo
   FROM   cte
   ORDER  BY ct, combo
   ) AS result;

结果是示例中的text数组。

请注意,使用RECURSIVE关键字时,您可以拥有任意数量的其他非递归CTE。

更通用

如果符合以下任何条件:

  • 数组元素不是唯一的(如'{A,B,B}')。
  • 基本数据类型不支持>运算符(如json)。
  • 数组元素非常大 - 以获得更好的性能。

使用行号而不是比较元素:

WITH RECURSIVE t AS (
   SELECT i::text, row_number() OVER () AS rn
   FROM   unnest('{A,B,B}'::text[]) i         -- duplicate element!
   )
, cte AS (
   SELECT i AS combo, rn, 1 AS ct
   FROM   t

   UNION  ALL
   SELECT cte.combo || t.i, t.rn, ct + 1
   FROM   cte
   JOIN   t ON t.rn > cte.rn
   )
SELECT ARRAY (   
   SELECT combo
   FROM   cte
   ORDER  BY ct, combo
   ) AS result;

或者在Postgres 9.4 +中使用WITH ORDINALITY

特殊情况:生成十进制数

要生成沿这些行包含5位数的十进制数字:

WITH RECURSIVE t AS (
   SELECT i
   FROM   unnest('{1,2,3,4,5}'::int[]) i
   )
, cte AS (
   SELECT i AS nr, i
   FROM   t

   UNION  ALL
   SELECT cte.nr * 10 + t.i, t.i
   FROM   cte
   JOIN   t ON t.i > cte.i
   )
SELECT ARRAY (   
   SELECT nr
   FROM   cte
   ORDER  BY nr
   ) AS result;

SQL Fiddle展示所有。

答案 1 :(得分:1)

如果n很小<在图20中,可以使用位掩码方法找到所有可能的组合。它有2 ^ n种不同的组合。数字值0到 (2 ^ n - 1)代表其中一个组合。 例如n = 3

0代表{},空元素
2 ^ 3-1 = 7 = 111b表示元素,abc

伪代码如下

for b=0 to 2^n - 1 do #each combination
  res=""
  for i=0 to (n-1) do   # which elements are included

     if (b && (1<<i) != 0)
        res= res+arr[i]
    end
    print res
  end
end