1

As an example, I have a matrix [1,2,3,4,5]'. This matrix contains one column and 5 rows, and I have to generate a pair of points like (1,2),(1,3)(1,4)(1,5),(2,3)(2,4)(2,5),(3,4)(3,5)(4,5).

I have to store these values in 2 columns in a matrix. I have the following code, but it isn't quite giving me the right answer.

for s = 1:5;
    for tb = (s+1):5;
    if tb>s
        in = sub2ind(size(pairpoints),(tb-1),1);
        pairpoints(in) = s;
        in = sub2ind(size(pairpoints),(tb-1),2);
        pairpoints(in) = tb;
     end
    end
end

With this code, I got (1,2),(2,3),(3,4),(4,5). What should I do, and what is the general formula for the number of pairs?

rayryeng
  • 102,964
  • 22
  • 184
  • 193
Anisa
  • 11
  • 4
  • I'm removing the image-processing tag as it isn't related. – rayryeng Aug 13 '14 at 21:23
  • Also, you want to have unique combinations of pairs of two, so the formula is actually `nchoosek` (alluding to @GeoffHayes). As such, given `N` items to choose from and choosing `k` elements at a time, you have `N! / (k!*(N-k)!)` possible pairs. In your case, `N = 5` and `k = 2`, and therefore: `5! / (2!*3!) = 10` – rayryeng Aug 13 '14 at 21:28

2 Answers2

3

One way, though is limited depending upon how many different elements there are to choose from, is to use nchoosek as follows

 pairpoints = nchoosek([1:5],2)

 pairpoints =
   1     2
   1     3
   1     4
   1     5
   2     3
   2     4
   2     5
   3     4
   3     5
   4     5

See the limitations of this function in the provided link.

An alternative is to just iterate over each element and combine it with the remaining elements in the list (assumes that all are distinct)

pairpoints = [];
data       = [1:5]';

len        = length(data);

for k=1:len
     pairpoints = [pairpoints ; [repmat(data(k),len-k,1) data(k+1:end)]];
end

This method just concatenates each element in data with the remaining elements in the list to get the desired pairs.

Try either of the above and see what happens!

Geoff
  • 1,603
  • 11
  • 8
1

Another suggestion I can add to the mix if you don't want to rely on nchoosek is to generate an upper triangular matrix full of ones, disregarding the diagonal, and use find to generate the rows and columns of where the matrix is equal to 1. You can then concatenate both of these into a single matrix. By generating an upper triangular matrix this way, the locations of the matrix where they're equal to 1 exactly correspond to the row and column pairs that you are seeking. As such:

%// Highest value in your data
N = 5;
[rows,cols] = find(triu(ones(N),1));
pairpoints = [rows,cols]

pairPoints = 

 1     2
 1     3
 2     3
 1     4
 2     4
 3     4
 1     5
 2     5
 3     5
 4     5

Bear in mind that this will be unsorted (i.e. not in the order that you specified in your question). If order matters to you, then use the sortrows command in MATLAB so that we can get this into the proper order that you're expecting:

pairPoints = sortrows(pairPoints)

pairPoints = 

 1     2
 1     3
 1     4
 1     5
 2     3
 2     4
 2     5
 3     4
 3     5
 4     5

Take note that I specified an additional parameter to triu which denotes how much of an offset you want away from the diagonal. The default offset is 0, which includes the diagonal when you extract the upper triangular matrix. I specified 1 as the second parameter because I want to move away from the diagonal towards the right by 1 unit so I don't want to include the diagonal as part of the upper triangular decomposition.


for loop approach

If you truly desire the for loop approach, going with your model, you'll need two for loops and you need to keep track of the previous row we are at so that we can just skip over to the next column until the end using this. You can also use @GeoffHayes approach in using just a single for loop to generate your indices, but when you're new to a language, one key advice I will always give is to code for readability and not for efficiency. Once you get it working, if you have some way of measuring performance, you can then try and make the code faster and more efficient. This kind of programming is also endorsed by Jon Skeet, the resident StackOverflow ninja, and I got that from this post here.

As such, you can try this:

pairPoints = []; %// Initialize
N = 5; %// Highest value in your data
for row = 1 : N
    for col = row + 1 : N
        pairPoints = [pairPoints; [row col]]; %// Add row-column pair to matrix
    end
end

We get the equivalent output:

pairPoints =

 1     2
 1     3
 1     4
 1     5
 2     3
 2     4
 2     5
 3     4
 3     5
 4     5

Small caveat

This method will only work if your data is enumerated from 1 to N.


Edit - August 20th, 2014

You wish to generalize this to any array of values. You also want to stick with the for loop approach. You can still keep the original for loop code there. You would simply have to add a couple more lines to index your new array. As such, supposing your data array was:

dat = [12, 45, 56, 44, 62]; 

You would use the pairPoints matrix and use each column to subset the data array to access your values. Also, you need to make sure your data is a column vector, or this won't work. If we didn't, we would be creating a 1D array and concatenating rows and that's not obviously what we're looking for. In other words:

dat = [12, 45, 56, 44, 62];
dat = dat(:); %// Make column vector - Important! 
N = numel(dat); %// Total number of elements in your data array
pairPoints = []; %// Initialize

%// Skip if the array is empty
if (N ~= 0)
    for row = 1 : N
        for col = row + 1 : N
            pairPoints = [pairPoints; [row col]]; %// Add row-column pair to matrix
        end
    end

    vals = [dat(pairPoints(:,1)) dat(pairPoints(:,2))];
else
    vals = [];

Take note that I have made a provision where if the array is empty, don't even bother doing any calculations. Just output an empty matrix.

We thus get:

vals =

12    45
12    56
12    44
12    62
45    56
45    44
45    62
56    44
56    62
44    62
Community
  • 1
  • 1
rayryeng
  • 102,964
  • 22
  • 184
  • 193
  • 1
    Aha use the subscripts! :D – Yvon Aug 13 '14 at 22:30
  • these are general values, if i want to store some matrix values like this then what should i do , for example i have to make pairs for values {12 , 45, 56,44, } then how to generate that kind of matrix , because the above code only generate from 1... to onward values , kindly guide me thanks – Anisa Aug 20 '14 at 13:42
  • @user3781516 That's easy. You would just include a few more lines. I'll update my answer. – rayryeng Aug 20 '14 at 13:55
  • thank you it works , there is a little problem if we have zero values in matrix then it gives error , what should i do – Anisa Aug 21 '14 at 14:35
  • Obviously it won't work. You need a single `if` statement that skips over this if there are no elements. I'll edit once more. – rayryeng Aug 21 '14 at 14:36