2010-11-12 1 views
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

то, что вы ищете, называется «декартовым произведением» векторов. У вас может быть какая-то удача. –

ответ

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', по сути, так же, как и в ответе Amro, с ошибкой проверки сверху. – lodhb

+0

Да, спасибо, что я искал .. :-) – tim

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 мощный разделенные запятыми списки вместо ячеек массивов для высокой производительности,

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

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

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

Использование cat и reshape сокращает время выполнения почти в два раза. Этот подход был продемонстрирован в my answer to an different question и more formally by Luis Mendo.

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 

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