Подтвердить что ты не робот

Как найти все подмножества множества с ровно n элементами?

Я пишу программу на Python, и я понял, что проблема, которую мне нужно решить, требует от меня заданного набора S с элементами n (| S | = n) для проверки функции на всех возможных подмножеств некоторого порядка m (т.е. с m числом элементов). Чтобы использовать ответ для создания частичного решения, а затем повторите попытку со следующим порядком m = m + 1, пока m = n.

Я собираюсь написать решение формы:

def findsubsets(S, m):
    subsets = set([])
    ...
    return subsets

Но зная Python, я ожидал, что решение уже существует.

Каков наилучший способ для этого?

4b9b3361

Ответ 1

itertools.combinations является вашим другом, если у вас есть Python 2.6 или выше. В противном случае проверьте ссылку для реализации эквивалентной функции.

import itertools
def findsubsets(S,m):
    return set(itertools.combinations(S, m))

Ответ 2

Используя каноническую функцию, чтобы получить poweret из рецепт itertools страница:

from itertools import chain, combinations

def powerset(iterable):
    """
    powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)
    """
    xs = list(iterable)
    # note we return an iterator rather than a list
    return chain.from_iterable(combinations(xs,n) for n in range(len(xs)+1))

Используется как:

>>> list(powerset("abc"))
[(), ('a',), ('b',), ('c',), ('a', 'b'), ('a', 'c'), ('b', 'c'), ('a', 'b', 'c')]

>>> list(powerset(set([1,2,3])))
[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]

наборы, если вы хотите, чтобы вы могли использовать объединение, пересечение и т.д.:

>>> map(set, powerset(set([1,2,3])))
[set([]), set([1]), set([2]), set([3]), set([1, 2]), set([1, 3]), set([2, 3]), set([1, 2, 3])]

>>> reduce(lambda x,y: x.union(y), map(set, powerset(set([1,2,3]))))
set([1, 2, 3])

Ответ 3

Здесь однострочный, который дает вам все подмножества целых чисел [0..n], а не только подмножества заданной длины:

from itertools import combinations, chain
allsubsets = lambda n: list(chain(*[combinations(range(n), ni) for ni in range(n+1)]))

например,

>> allsubsets(3)
[(), (0,), (1,), (2,), (0, 1), (0, 2), (1, 2), (0, 1, 2)]

Ответ 4

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

Следующий алгоритм будет иметь все подмножества, исключающие пустое множество.

list * subsets(string s, list * v) {

    if(s.length() == 1) {
        list.add(s);    
        return v;
    }
    else
    {
        list * temp = subsets(s[1 to length-1], v);
        int length = temp->size();

        for(int i=0;i<length;i++) {
            temp.add(s[0]+temp[i]);
        }

        list.add(s[0]);
        return temp;
    }
}

Итак, например, если s = "123", то вывод:

1
2
3
12
13
23
123

Ответ 5

Без использования itertools:

В Python 3 вы можете использовать yield from для добавления метода генератора подмножества в класс buit-in set:

class SetWithSubset(set):
    def subsets(self):
        s1 = []
        s2 = list(self)

        def recfunc(i=0):            
            if i == len(s2):
                yield frozenset(s1)
            else:                
                yield from recfunc(i + 1)
                s1.append(s2[ i ])
                yield from recfunc(i + 1)
                s1.pop()

        yield from recfunc()

Например, ниже фрагмент работает как ожидалось:

x = SetWithSubset({1,2,3,5,6})
{2,3} in x.subsets()            # True
set() in x.subsets()            # True
x in x.subsets()                # True
x|{7} in x.subsets()            # False
set([5,3]) in x.subsets()       # True - better alternative: set([5,3]) < x
len(x.subsets())                # 32