3

I wanted to find all combinations of elements from a set of vectors. I found the following answer which works perfectly. However, some of my vectors are paired together. For instance, if I have the vector [15, 20] and [60, 70], I would like to get the combination [15, 60] and [20, 70] only (because 15 can't be combined with 70).

Hence, for the following vectors:

vectors = {[1 2], [3 6 9], [10 20 30]} % [3 6 9] and [10 20 30] are paired

, should give

combs = [ 1     3    10
          1     6    20
          1     9    30
          2     3    10
          2     6    20
          2     9    30 ]

For this simple example, I'm able to use the combination code from the link by using vectors = {[1 2], [3 6 9]}, and by doing a concatenation for generating the third column:

combs = [combs, repmat([10 20 30], 1, size(combs, 1)/size([10 20 30], 2))'];

However, my cases are not that simple. For example, I would to have a code that works for a vectors:

vectors = {[1 2], [3 6 9], [10 20 30], [3 4 5], [55 66 77], [555 666 777], [101 201]} 
% [3 6 9] and [10 20 30] are a pair. 
% [55 66 77] and [555 666 777] are a pair.
Community
  • 1
  • 1
m_power
  • 3,156
  • 5
  • 33
  • 54

1 Answers1

2

You first need to define which vectors are "linked". Using your example,

vectors = {[1 2] [3 6 9] [10 20 30] [3 4 5] [55 66 77] [555 666 777] [101 201]};
linked = [1 2 2 3 4 4 5]; %// equal numbers mean those vectors are linked

Then you can use a slight modification of the referred answer:

  1. Reduce each vector to an equivalent vector of values 1,2,3,... Let's call that "int-vector".

  2. Generate combinations considering only one "representative" int-vector from each linked set of vectors.

  3. Fill copied values (columns) for the remaining int-vectors (linked to their representatives). This is why we use int-vectors instead of vectors: each non-representative is just a copy of its representative.

  4. Use indexing to translate from int-vectors to actual vectors.

Code:

intVectors = cellfun(@(x) 1:numel(x), vectors, 'uniformoutput', 0); %// transform
%// each vector into integers 1, 2, 3,...
[~, u, v] = unique(linked); 
uIntVectors = intVectors(u); %// choose one int-vector as representative of each
%// linked set
m = numel(vectors); %// number of vectors
n = numel(uIntVectors); %// number of representatives (int-vectors)
combs = cell(1,n);
[combs{end:-1:1}] = ndgrid(uIntVectors{end:-1:1});
combs = combs(:,v); %// include non-representatives (linked int-vectors) 
combs = cat(m+1, combs{:});
combs = reshape(combs,[],m); %// combinations of representatives (int-vectors)
num = max(combs, [], 1); %// number of elements of each vector
vectorsCat = [vectors{:}]; %// concatenate all vectors
cnum = cumsum(num(1:end-1));
combs(:,2:end) = bsxfun(@plus, combs(:,2:end), cnum); %// transform integers
%// so that they can index vectorsCat
combs = vectorsCat(combs); %// do the indexing to get final result

Let's simplify your example a litle for the sake of brevity:

vectors = {[1 2], [3 6 9], [10 20 30], [3 4 5]};
linked = [1 2 2 3]; 

produces

1     3    10     3
1     3    10     4
1     3    10     5
1     6    20     3
1     6    20     4
1     6    20     5
1     9    30     3
1     9    30     4
1     9    30     5
2     3    10     3
2     3    10     4
2     3    10     5
2     6    20     3
2     6    20     4
2     6    20     5
2     9    30     3
2     9    30     4
2     9    30     5
Luis Mendo
  • 110,752
  • 13
  • 76
  • 147