Комбинации с повторением

Я использую Mathematica 7, и с помощью функции пакета combinatorica я могу получить все комбинации определенного числа из списка элементов, где порядок не имеет значения и нет повторений. Например:

in: KSubsets[{a, b, c, d}, 3]
out: {{a, b, c}, {a, b, d}, {a, c, d}, {b, c, d}}

Я не могу найти функцию, которая выдала бы мне все комбинации определенного числа из списка элементов, где порядок не имеет значения и есть повторение. т.е. приведенный выше пример будет включать в вывод такие элементы, как {a, a, b}, {a, a, a}, {b, b, b} ... и т. д.

Может потребоваться пользовательская функция. Если я смогу придумать один, я отправлю ответ, но пока я не вижу очевидного решения.

Изменить: в идеале вывод не будет содержать дублирования комбинации, например. Кортежи [{a, b, c, d}, 3] вернут список, содержащий два элемента, такие как {a, a, b} и {b, a, a}, которые с точки зрения комбинаций являются одинаковыми.


person dbjohn    schedule 30.11.2010    source источник


Ответы (4)


Вы можете кодировать каждую комбинацию как {na,nb,nc,nd}, где na указывает количество появлений a. Затем задача состоит в том, чтобы найти все возможные комбинации из 4 неотрицательных целых чисел, которые в сумме дают 3. IntegerPartition дает быстрый способ сгенерировать все такие комбинации, где порядок не имеет значения, и вы следуете за ним с помощью Permutations для учета различных заказов.

vars = {a, b, c, d};
len = 3;
coef2vars[lst_] := 
 Join @@ (MapIndexed[Table[vars[[#2[[1]]]], {#1}] &, lst])
coefs = Permutations /@ 
   IntegerPartitions[len, {Length[vars]}, Range[0, len]];
coef2vars /@ Flatten[coefs, 1]

Просто для удовольствия, вот сравнение времени между IntegerPartitions и Tuples для этой задачи в лог-секундах.

approach1[numTypes_, len_] := 
  Union[Sort /@ Tuples[Range[numTypes], len]];
approach2[numTypes_, len_] := 
  Flatten[Permutations /@ 
    IntegerPartitions[len, {numTypes}, Range[0, len]], 1];

plot1 = ListLinePlot[(AbsoluteTiming[approach1[3, #];] // First // 
       Log) & /@ Range[13], PlotStyle -> Red];
plot2 = ListLinePlot[(AbsoluteTiming[approach2[3, #];] // First // 
       Log) & /@ Range[13]];
Show[plot1, plot2]


(источник: yaroslavvb .com)

person Yaroslav Bulatov    schedule 30.11.2010
comment
может показаться слишком сложным? - person Yaroslav Bulatov; 01.12.2010

Вот простое решение, которое использует преимущества встроенных функций Mathetmatica Subsets и, таким образом, обеспечивает хороший баланс между простотой и производительностью. Существует простая биекция между k-подмножествами [n + k-1] и k-комбинациями [n] с повторением. Эта функция преобразует подмножества в комбинации с повторением.

CombWithRep[n_, k_] := #-(Range[k]-1)&/@Subsets[Range[n+k-1],{k}]

So

CombWithRep[4,2]

дает

{{1,1},{1,2},{1,3},{1,4},{2,2},{2,3},{2,4},{3,3},{3,4},{4,4}}
person Jeffrey Liese    schedule 22.02.2017

Небольшой вариант элегантного метода, данного High Performance Mark:

Select[Tuples[{a, b, c, d}, 3], OrderedQ]

Перестановки немного более универсальны (но это не то, что вы ищете?)

Например:

Select[Permutations[
  Sort@Flatten@ConstantArray[{a, b, c, d}, {3}], {2, 3}], OrderedQ]

дает следующие

alt text

Редактировать:

Select[Tuples[Sort@{a, b, d, c}, 3], OrderedQ]

наверное лучше

Редактировать-2

Конечно, можно использовать и кейсы. Например

Cases[Permutations[
  Sort@Flatten@ConstantArray[{a, b, d, c}, {3}], {2, 3}], _?OrderedQ]

Редактировать-3.

Два подхода будут отличаться, если список содержит повторяющийся элемент. Например, результат следующего (подход 2) будет содержать дубликаты (которые могут быть, а могут и не быть желательными):

Select[Tuples[{a, b, c, d, a}, 3], OrderedQ]

От них легко избавиться:

Union@Select[Tuples[{a, b, c, d, a}, 3], OrderedQ]

Следующее оценивается как «Истина» (удалить повторяющиеся элементы из списка, представленного для подхода 2, и отсортировать список, созданный для подхода 1 (метод High Performance Mark):

lst = RandomInteger[9, 50]; 
Select[Union@Sort@Tuples[lst, 3], OrderedQ] == 
 Sort@DeleteDuplicates[Map[Sort, Tuples[lst, 3]]]

как и следующее (удалить дубликаты из выходных данных подхода 2, отсортировать выходные данные подхода 1):

lst = RandomInteger[9, 50]; 
Union@Select[Sort@Tuples[lst, 3], OrderedQ] == 
 Sort@DeleteDuplicates[Map[Sort, Tuples[lst, 3]]]

Извини за это!

person tomd    schedule 03.12.2010
comment
Вы можете отказаться от сортировки, если выберете Select [#, OrderedQ] - person Yaroslav Bulatov; 03.12.2010

person    schedule
comment
Обратите внимание, что Sort[#]& - это то же самое, что просто Sort. - person dreeves; 01.12.2010
comment
@TomD - Да, действительно, и моя первая версия использовала Union, затем я обнаружил DeleteDuplicates в документации, и его имя более показательно для того, что он делает в этом случае. - person High Performance Mark; 02.12.2010