Генерация всех возможных комбинаций элементов некоторых векторов (декартово произведение) - PullRequest
32 голосов
/ 12 ноября 2010

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

Например, для [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? Уже есть предопределенная функция, которая может выполнить эту задачу?

Ответы [ 4 ]

47 голосов
/ 13 ноября 2010

Рассмотрим это решение, используя функцию 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);
16 голосов
/ 12 ноября 2010

Попробуйте 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
11 голосов
/ 24 апреля 2014

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

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

Как и в своем ответе Амро, синтаксис списков, разделенных запятыми (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 голосов
/ 13 января 2018

мы также можем использовать инструкцию '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 

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

...