LINUX.ORG.RU

Ищу алгоритм генерации всех сочетаний элементов списка

 ,


1

2

Есть список длиной n. Нужно получить список списков всех возможных сочетаний длиной от 1 до n без повторов и в любой последовательности.

Не уверен, что это верный термин, но лучше ничего не нагуглилось.

Пример, чтобы было всем понятно:

1 2 3

1
2
3
1 2
1 3
2 3
1 2 3

Если код будет выдать, к примеру, 3 2, а не 2 3 - не страшно. Мне порядок не важен.

Видимо не по тому слову гуглю, ибо выдаёт только примеры перестановки в списке фиксированной длины. Типа «список сочетаний из 4-х цифр». Но мне это не нужно.

Я конечно слепил костыль, но мне кажется, что есть готовый алгоритм для данной задачи.

PS: нет, это не лаба, и не тестовое задание. Я пытаюсь написать тест для проги, который будет перебирать все возможные аргументы CLI.

★★★★★

allSets [] = [[]]
allSets (x:xs) = map (x:) (allSets xs) ++ allSets xs
Waterlaz ★★★★★
()
Ответ на: комментарий от LinuxDebian

товарищ один из тех, кто жалуется на злой С++, заставляющий писать сегфолтящийся говнокод. и такие вот вопросы задаёт. я думаю, это взаимосвязано. а С++ виноват потому что ну не себя же винить.

ckotinko ☆☆☆
()
Ответ на: комментарий от ckotinko

Понятно теперь. А вопрос то детский действительно...

LinuxDebian ★★★★
()
Ответ на: комментарий от ckotinko

Сказал человек, не умеющий в русский язык.

PS: статистика показывает, что только лоровские аналитики могут писать код без сегфолтов.

RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от hateyoufeel

Ты так гойворишь, будто список не монада, а filterM имеет аналог в List.

nezamudich ★★
()

Этому треду не хватает реализации на си.

#include <stdio.h>

int main(int argc, char ** argv)
{
        unsigned N;
        if (argc!=2 || !sscanf(argv[1], "%u", &N) || (N>=sizeof(unsigned long)*8))
                return 1;
        for (unsigned long i=(1lu<<N)-1;i>0;--i)
        {
                for (int bit=0, k=i;k;k>>=1,++bit)
                        if (k&1)
                                printf("%d ", bit);
                printf("\n");
        }
}

legolegs ★★★★★
()
Ответ на: комментарий от RazrFalcon

Честная реализация с генерацией списков на голом си займёт денёк-другой, учитывая отладку. Внезапнейше.

nezamudich ★★
()
Ответ на: комментарий от RazrFalcon

Ну сам сравни:

1) «получить список списков всех возможных сочетаний...»

2) вывести на экран числа от 1 до n в двоичной системе счисления

Waterlaz ★★★★★
()

literate программинг

Есть список длиной n. Нужно получить список списков

судя по нижеследующему примеру ТСом задан формат списки2уровня разделяются пустыми строками списки1уровня разделяются переводами строк элементы списка1уровня пробелом.

 псевдАcode> читануть список1уровня L; n <- длина L
 псевдАcode> выдать начало списка 2уровня Z
 псевдАcode> out=[];tr(1,n,L)
 псевдАcode> выдать конец списка 2уровня Z
судя по очерёдности(от коротких к полному) выдачи подсписков(которые списки1уровня) у ТСа в рекурсивной tr стоит пытатся от последних до следующего
псевдАcode> tr(from, last,ref above) is 
псевдАcode> if from>last {output(out);return}
псевдАcode> push2out(L[from])
псевдАcode> for i=last downto from do {tr(i+1,n,L)}
псевдАcode> drop5out();
для полного совпадения выдачи с примером ТС реверсировать входной список1уровня

тогда выдача списка2уровня состоящая начиная с пустого списка1уровня и заканчивая полным дублем входа


зы output есть печать стека накопления.
зы push2out вталкивание элемента в стек
зы drop5out дискард вершины стека

anonymous
()
11 апреля 2017 г.

В итоге оказалось, что это абсолютно бесполезно.

У меня порядка 70-и элементов в списке, ака 1000050000 комбинаций. Проверка каждой комбинации занимает пару минут. В итоге мне нужно 100 лет, чтобы всё проверить...

RazrFalcon ★★★★★
() автор топика
Последнее исправление: RazrFalcon (всего исправлений: 1)
Ответ на: комментарий от ZERG

ЛОР: олимпиадное программирование не нужно ЛОР: программисты, не знающие математики, не нужны

вы там уже, блин, определитесь

anonymous
()
Ответ на: комментарий от anonymous

Олимпиадное программирование != математика.

peregrine ★★★★★
()
Ответ на: комментарий от anonymous

Так никто же не просит быть олимпиадником. Сама задача из наивной теории множеств, а уж если ты не оцениваешь сложность алгоритма и просто гонишь его as it is, то что тут можно сказать.

ZERG ★★★★★
()
6 марта 2018 г.

Шо? Опять?

Ну с той штукой:

Ищу специфическую реализацию фильтра размытия по Гауссу

понятно было на счёт того, что там реально нужно было понимание чуть больше чем тупой перебор.

А тут что за сложности?!

Помочь ешё раз?

Хоть бы отписался по теме, что круто тебе запилил алгоритм.

Serg_HIS
()

Сочетания на перлятине, чисто proof of concept. Так, вообще, это подправленный вариант реализации динамического количества вложенных циклов - V[0], V[1], V[2]... - это индексы вложенных циклов, количество вложений задаётся переменной $depth. Нужно было перебрать все возможные сочетания красителей для расчёта рецептур.

#!/usr/bin/perl

$depth = 3;
$max = 6;
@v = ();

for( $vt = 1, $i = 1; $i <= $depth; $i++ ) { $vt = $vt * ( $max - $i + 1 ) / $i; }

printf( "Number of %d-combinations from %d: %d\n", $depth, $max, $vt );

# only N-combinations
for( $i = 0; $i < $depth; $i++ ) { $v[$i] = $i; }
# 1 ... N - combinations 
#for( $i = 0; $i < $depth; $i++ ) { $v[$i] = 0; }

for( $vc = 0; ; $vc++ )
{
    print "C" . $vc . ":\t". join( " ", @v ) ."\n";

    for( $l = $max, $d = $depth - 1; $d >= 0; $d--, $l-- )
    {
        if( ++$v[$d] < $l ) { last; }
    }

    if( $d < 0 ) { last; }

    $l = $max - ( $depth - 1 - ++$d );

    for( ; $d < $depth ; $d++, $l++ )
    {
        if( $v[$d] >= $l ) { $v[$d] = $v[$d-1] + 1; }
    }
}

$max - количество элементов, из которых надо строить сочетания.

$depth - количество элементов в сочетании.

В сочетании могут быть только разные элементы. сочетания типа 2 3 4 и 4 3 2 считаются одинаковыми.

Пример выдаст такое:

Number of 3-combinations from 6: 20
C0:     0 1 2
C1:     0 1 3
C2:     0 1 4
C3:     0 1 5
C4:     0 2 3
C5:     0 2 4
C6:     0 2 5
C7:     0 3 4
C8:     0 3 5
C9:     0 4 5
C10:    1 2 3
C11:    1 2 4
C12:    1 2 5
C13:    1 3 4
C14:    1 3 5
C15:    1 4 5
C16:    2 3 4
C17:    2 3 5
C18:    2 4 5
C19:    3 4 5

Stanson ★★★★★
()
Последнее исправление: Stanson (всего исправлений: 1)

Это часом не декартово произведение ты искал?

KennyMinigun ★★★★★
()

Quick'n'dirty: https://play.golang.org/p/hj2OXXXV46y

package main

import "fmt"

func main() {
	input := []int{1, 2, 3, 4, 5}
	ch := make(chan []int)
	go func(v []int) {
		defer close(ch)
		for i := 0; i <= len(v); i++ {
			car, cdr := v[:i:i], v[i:]
			for _, x := range cdr {
				ch <- append(car, x)
			}
		}
	}(input)
	for v := range ch {
		fmt.Println(v)
	}
}

Output:

[1]
[2]
[3]
[4]
[5]
[1 2]
[1 3]
[1 4]
[1 5]
[1 2 3]
[1 2 4]
[1 2 5]
[1 2 3 4]
[1 2 3 5]
[1 2 3 4 5]

beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 3)
Ответ на: комментарий от RazrFalcon

весна, лоровский программист потихоньку отходит от зимней спячки

anonymous
()

Тред не читал.

https://play.rust-lang.org/?gist=3355aece2f3a9a51c3cca066f9bab669&version...
Уникальные элементы сам отфильтровывай, я и так притомился возюкаться.

Алгоритм честно позаимствовал из питоньего itertools: https://docs.python.org/3/library/itertools.html#itertools.permutations (любопытный, кстати, опыт в плане сравнения выразительности ЯП).

Upd.: Clippy немного ругается, но код-то не боевой.

Virtuos86 ★★★★★
()
Последнее исправление: Virtuos86 (всего исправлений: 3)
Ответ на: комментарий от Virtuos86

Вы растофаги все альтернативно одареные? Не знаете даже какие инструменты у вас есть, просто фейспалм. Про алгоритм из букваря я уж молчу. Матан, лол.

anonymous
()
Ответ на: комментарий от anonymous

Что сказать-то хотел? Ну да, я поискал по https://doc.rust-lang.org/stable/std/ подходящие возможности в векторах, но не нашел.

Про алгоритм из букваря я уж молчу.

Какое из решений в треде является алгоритмом из букваря? Давай, оценю.

Virtuos86 ★★★★★
()
Ответ на: комментарий от RazrFalcon

Проверка каждой комбинации занимает пару минут. В итоге мне нужно 100 лет, чтобы всё проверить...

Хипсторы постигают мир. Учились на факультете искусств, батенька?

anonymous
()
Ответ на: комментарий от beastie

Если порядок не важен, то это двоичные числа от 1 до 2^N.

//gcc  -o tst tst.c
#include <stdio.h>

#define N 5

int b[N];

int main()
{
    int i, j;
    for (i = 0; i < N; i++)
        b[i] = (1 << i);
    for (i = 1; i < (1 << N); i++) {
        printf("[");
        for (j = 0; j < N; j++) {
            if ((i & b[j]) != 0)
                printf(" %d", j + 1);
        }
        printf(" ]\n");
    }
    return 0;
}
вроде так.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.