Form a matrix of combinations with vector sets / pairs
I wanted to find all combinations of elements from a set of vectors. I found the following answer which works great. However, some of my vectors are chained together. For example, if I have a vector [15, 20]
and [60, 70]
, I would only like to get a combination of [15, 60]
and [20, 70]
(because you 15
cannot combine with 70
).
Therefore, for the following vectors:
vectors = {[1 2], [3 6 9], [10 20 30]} % [3 6 9] and [10 20 30] are paired
must 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 can use the combination code from the link with vectors = {[1 2], [3 6 9]}
and doing the concatenation to generate the third column:
combs = [combs, repmat([10 20 30], 1, size(combs, 1)/size([10 20 30], 2))'];
However, my business is not so simple. For example, I would like to have some code that works for 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.
source to share
First, you need to determine which vectors are "related". 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 mentioned answer:
-
Reduce each vector to the equivalent vector of values ββ1,2,3, ... Let's call this "int-vector".
-
Create combinations based on only one "representative" int-vector from each related set of vectors.
-
Fill in the copied values ββ(columns) for the rest of the int vectors (associated with their representatives). This is why we use int vectors instead of vectors: each unrepresentative is just a copy of its representative.
-
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 litle example for 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
source to share