Генерация всех возможных комбинаций элементов некоторых векторов (декартово произведение)

31

Я хотел бы сгенерировать все возможные комбинации элементов заданного числа векторов.

Например, для [1 2], [1 2] и [4 5] я хочу сгенерировать элементы:

[1 1 4; 1 1 5; 1 2 4; 1 2 5; 2 1 4; 2 1 5; 2 2 4; 2 2 5]

Проблема в том, что я не знаю числа векторов, для которых мне нужно вычислить комбинации. В этом случае может быть 3, или может быть 10, и мне нужно обобщение. Не могли бы вы помочь мне в этом в MATLAB? Есть ли уже предопределенная функция, которая может выполнить эту задачу?

  • 10
    то, что вы ищете, называется «декартовым произведением» векторов. Возможно, вам повезет, что вы в поиске.
Теги:
cartesian-product
combinatorics

4 ответа

16
Лучший ответ

Попробуйте ALLCOMB в FileExchange.

Если вы храните векторы в массиве ячеек, вы можете запустить его следующим образом:

a = {[1 2], [1 2], [4 5]};
allcomb(a{:})
ans =

     1     1     4
     1     1     5
     1     2     4
     1     2     5
     2     1     4
     2     1     5
     2     2     4
     2     2     5
  • 6
    Обратите внимание, что ALLCOMB использует NDGRID по существу так же, как в ответе Амро, с NDGRID от ошибок сверху.
  • 0
    Да, спасибо, что я искал .. :-)
46

Рассмотрим это решение, используя функцию NDGRID:

sets = {[1 2], [1 2], [4 5]};
[x y z] = ndgrid(sets{:});
cartProd = [x(:) y(:) z(:)];

cartProd =
     1     1     4
     2     1     4
     1     2     4
     2     2     4
     1     1     5
     2     1     5
     1     2     5
     2     2     5

Или, если вы хотите общее решение для любого количества наборов (без необходимости создавать переменные вручную), используйте это определение функции:

function result = cartesianProduct(sets)
    c = cell(1, numel(sets));
    [c{:}] = ndgrid( sets{:} );
    result = cell2mat( cellfun(@(v)v(:), c, 'UniformOutput',false) );
end

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

cartProd = sortrows(cartProd, 1:numel(sets));

Кроме того, приведенный выше код не проверяет, нет ли у наборов повторяющихся значений (например: {[1 1] [1 2] [4 5]}). Добавьте эту строку, если хотите:

sets = cellfun(@unique, sets, 'UniformOutput',false);
11

Эти поздние ответы предоставляют два дополнительных решения, где второе решение (на мой взгляд) и улучшение решения ответа Amro с помощью ndgrid путем применения мощных списков разделенных запятыми MATLAB вместо массивов ячеек для высокой производительности,

  • Если у вас есть Neural Network Toolbox: используйте combvec
  • Если у вас нет инструментария, как это обычно бывает: ниже - еще один способ обобщить декартово произведение на любое количество множеств.

Как и Амро в своем ответе, синтаксис списков, разделенных запятыми (v{:}), снабжает входы и выходы ndgrid. Разница (четвертая строка) заключается в том, что она избегает cellfun и cell2mat, применяя списки, разделенные запятыми, снова, теперь как входы для cat:

N = numel(a);
v = cell(N,1);
[v{:}] = ndgrid(a{:});
res = reshape(cat(N+1,v{:}),[],N);

Использование cat и reshape сокращает время выполнения почти вдвое. Этот подход был продемонстрирован в моем ответе на другой вопрос и более формально Луисом Мендо.

0

мы также можем использовать инструкцию combvec в matlab

    no_inp=3 % number of inputs we want...in this case we have 3 inputs                  
    a=[1 2 3]
    b=[1 2 3]
    c=[1 2 3]

    pre_final=combvec(c,b,a)';
    final=zeros(size(pre_final));

    for i=1:no_inp
    final(:,i)=pre_final(:,no_inp-i+1);
    end
    final 

Надеюсь, это поможет. Удачи.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню