Объединить все комбинации строк, взятых k за раз

На основании некоторых других ответов, но этот будет отклонять программы с незаконными бинарными литералами. Ведущие нули являются необязательными.

template<bool> struct BinaryLiteralDigit;

template<> struct BinaryLiteralDigit<true> {
    static bool const value = true;
};

template<unsigned long long int OCT, unsigned long long int HEX>
struct BinaryLiteral {
    enum {
        value = (BinaryLiteralDigit<(OCT%8 < 2)>::value && BinaryLiteralDigit<(HEX >= 0)>::value
            ? (OCT%8) + (BinaryLiteral<OCT/8, 0>::value << 1)
            : -1)
    };
};

template<>
struct BinaryLiteral<0, 0> {
    enum {
        value = 0
    };
};

#define BINARY_LITERAL(n) BinaryLiteral<0##n##LU, 0x##n##LU>::value

Пример:

#define B BINARY_LITERAL

#define COMPILE_ERRORS 0

int main (int argc, char ** argv) {
    int _0s[] = { 0, B(0), B(00), B(000) };
    int _1s[] = { 1, B(1), B(01), B(001) };
    int _2s[] = { 2, B(10), B(010), B(0010) };
    int _3s[] = { 3, B(11), B(011), B(0011) };
    int _4s[] = { 4, B(100), B(0100), B(00100) };

    int neg8s[] = { -8, -B(1000) };

#if COMPILE_ERRORS
    int errors[] = { B(-1), B(2), B(9), B(1234567) };
#endif

    return 0;
}
0
задан afs76 16 January 2019 в 03:29
поделиться

1 ответ

Метод, описанный в цитируемом ответе, является статическим. Более удобным решением может быть использование рекурсии.

Пример данных:

drop table if exists my_table;
create table my_table(id int primary key, number int);
insert into my_table values
(1, 5), 
(2, 3), 
(3, 6), 
(4, 9), 
(5, 2);

Запрос, который находит 2 поднабора элементов в наборе из 5 элементов (комбинация k с k = 2):

with recursive recur as (
    select 
        id, 
        array[id] as combination, 
        array[number] as numbers, 
        number as sum
    from my_table
union all
    select 
        t.id, 
        combination || t.id, 
        numbers || t.number, 
        sum+ number
    from my_table t
    join recur r on r.id < t.id 
    and cardinality(combination) < 2            -- param k
)
select combination, numbers, sum/2.0 as average -- param k
from recur
where cardinality(combination) = 2              -- param k

 combination | numbers |      average       
-------------+---------+--------------------
 {1,2}       | {5,3}   | 4.0000000000000000
 {1,3}       | {5,6}   | 5.5000000000000000
 {1,4}       | {5,9}   | 7.0000000000000000
 {1,5}       | {5,2}   | 3.5000000000000000
 {2,3}       | {3,6}   | 4.5000000000000000
 {2,4}       | {3,9}   | 6.0000000000000000
 {2,5}       | {3,2}   | 2.5000000000000000
 {3,4}       | {6,9}   | 7.5000000000000000
 {3,5}       | {6,2}   | 4.0000000000000000
 {4,5}       | {9,2}   | 5.5000000000000000
(10 rows)   

Тот же запрос для k = 3 дает:

 combination | numbers |      average       
-------------+---------+--------------------
 {1,2,3}     | {5,3,6} | 4.6666666666666667
 {1,2,4}     | {5,3,9} | 5.6666666666666667
 {1,2,5}     | {5,3,2} | 3.3333333333333333
 {1,3,4}     | {5,6,9} | 6.6666666666666667
 {1,3,5}     | {5,6,2} | 4.3333333333333333
 {1,4,5}     | {5,9,2} | 5.3333333333333333
 {2,3,4}     | {3,6,9} | 6.0000000000000000
 {2,3,5}     | {3,6,2} | 3.6666666666666667
 {2,4,5}     | {3,9,2} | 4.6666666666666667
 {3,4,5}     | {6,9,2} | 5.6666666666666667
(10 rows)

Конечно, вы можете удалить numbers из запроса, если они вам не нужны.

0
ответ дан klin 16 January 2019 в 03:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: