Matlab: sort an array to ascending order in terms of binary interpretation - matlab

The array contains binary numbers per line: one row means one binary number. They are in no order so I am trying to find a command by which I can sort them to ascending order, how to do it?
Input
>> [1 0 0 1 1; 0 0 1 0 0; 1 0 1 0 0]
ans =
1 0 0 1 1
0 0 1 0 0
1 0 1 0 0
0 0 0 0 1
Goal: by which command I can get by the input the below output?
0 0 0 0 1
0 0 1 0 0
1 0 0 1 1
1 0 1 0 0

You can do it by converting to strings (num2str) and then from binary string to number (bin2dec):
[vv ii] = sort(bin2dec(num2str(data)));
data_sorted = data(ii,:);

Based on my suggestion in the comments, "you should be able to do a radix sort using sortrows on columns n down to 1.", the OP got the following code working:
>> A=[1 0 0 1 1; 0 0 1 0 0; 1 0 1 0 0;0 0 0 0 1];sortrows(A)
ans =
0 0 0 0 1
0 0 1 0 0
1 0 0 1 1
1 0 1 0 0
And has now included Luis' cool idea for indexing.

Beaker answered in the comment "you should be able to do a radix sort using sortrows on columns n down to 1." -- and it works! Then Luis Mendo had a method to store the original positioning so putting the ideas together, vuola!
>> A=[1 0 0 1 1; 0 0 1 0 0; 1 0 1 0 0;0 0 0 0 1]
[vv ii]=sortrows(A)
A =
1 0 0 1 1
0 0 1 0 0
1 0 1 0 0
0 0 0 0 1
vv =
0 0 0 0 1
0 0 1 0 0
1 0 0 1 1
1 0 1 0 0
ii =
4
2
1
3

Related

Advanced Search and Remove in special Matrix

I have this matrix
X= [2 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 250;
3 0 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 250;
2 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 250;
3 0 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 250;
4 0 0 1 0 1 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 250;
3 0 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 250;
2 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 250;
4 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 1 1 0 0 0 0 250;
3 0 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 250;
3 1 1 1 0 0 1 0 0 1 0 0 1 0 0 0 0 1 0 1 0 0 400]
I need to do three different sequence things in this matrix:
1- Search in this matrix to the following sequence 1 1 0 0 0 and write those rows that have this characteristic in new matrix (like row 1).
2- Use the matrix that generate in the first step and remove from it to the rows that have the same number in the same digits (like row 1,3,7) but at the same time keep only one row of each one (in the case of row 1,3,7 keep row 1 and remove other rows) .
3- use the matrix that generate in the second step and remove from this matrix any row that have following sequence 1 1 1 (like row 8) and put the other rows in this matrix in new matrix.
%Step-1
% Converting the matrix into a string, appending a semi-colon for similarity and removing the brackets from the string
req=mat2str(X); req(end)=';' ; req=req(2:end);
% Searching the sequence: 1 1 0 0 0
sp1=strfind(req, '1 1 0 0 0');
% Storing those rows of X in req matrix which contain the sequence
req=X(unique(ceil([sp1]/(size(req,2)/size(X,1)))),:);
%Step-2
req= unique(req,'rows');
%Step-3
% Converting the matrix into a string, appending a semi-colon for similarity and removing the brackets from the string
reqtemp=mat2str(req); reqtemp(end)=';' ; reqtemp=reqtemp(2:end);
% Searching the sequence: 1 1 1
sp1=strfind(reqtemp, '1 1 1');
% Removing those rows which contain the sequence
req(unique(ceil([sp1]/(size(reqtemp,2)/size(req,1)))),:)=[];

How do I create random matrix where each column is all zeroes except for one random row?

I want to create a matrix of size m-by-n where all elements in a column are 0 except one element which is 1. That one element must be at a random position.
eg.
[0 1 0 0 0
0 0 1 0 0
1 0 0 1 0
0 0 0 0 0
0 0 0 0 1]
To add some variety, here's another approach:
m = 4;
n = 5;
[~, result] = sort(rand(m,n));
result = double(result==1);
This gives, for example,
result =
0 0 0 0 1
0 1 0 0 0
1 0 0 1 0
0 0 1 0 0
You can also use rand and max to do the job:
m=4;
n=5;
R=rand(m,n);
result = bsxfun(#eq, R, max(R,[],1))
On my machine it gave:
1 1 0 0 0
0 0 0 0 0
0 0 1 0 1
0 0 0 1 0
How it works: Generating a random matrix, R, and then setting to 1 the entry corresponding to the maximal element at each column. No need for sorting.
Regarding the original answer of Divakar, since it uses randperm it is restricted to square matrix only, and it will only produce random permutation matrices.
One possible way to correct his solution is to use randi instead of randperm:
result = bsxfun( #eq, (1:m)', randi(m, 1, n ) )
May give this output:
1 0 1 0 0
0 0 0 0 0
0 0 0 0 0
0 1 0 1 1
As for the answer of bla, using accumarry can save the use of zeros and sub2ind:
m=5; n=10;
R=randi(m,n,1);
A = accumarray( {R, (1:n)' }, 1, [m n] )
May give this output:
0 0 0 0 1 0 0 1 0 0
0 1 0 0 0 0 1 0 1 0
1 0 0 1 0 0 0 0 0 1
0 0 0 0 0 1 0 0 0 0
0 0 1 0 0 0 0 0 0 0
Another idea I have is to create the identity matrix of size m x m, then use randi with a range from 1 up to m to create a vector of n elements long. After, you'd use this vector to access the columns of the identity matrix to complete the random matrix you desire:
m = 5; n = 5; %// Given your example
M = eye(m);
out = M(:,randi(m, n, 1));
Here's one possible run of the above code:
out =
1 0 0 0 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 0
0 1 1 0 1
here's an example using randi:
m=5; n=10;
A=zeros(m,n);
R=randi(m,n,1);
A(sub2ind(size(A),R',1:n))=1
A =
0 0 0 0 0 0 0 1 0 1
0 0 1 0 0 0 0 0 0 0
0 1 0 1 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0 0
1 0 0 0 0 0 1 0 1 0
You can use sparse with randi for a one-liner, like so -
full(sparse(randi(m,1,n),1:n,1,m,n))
Sample run -
>> m = 5; n = 6;
>> full(sparse(randi(m,1,n),1:n,1,m,n))
ans =
0 1 0 0 0 1
0 0 1 1 0 0
0 0 0 0 0 0
1 0 0 0 1 0
0 0 0 0 0 0

Extract multiple indices from matrix

I want to access multiple indices of a matrix as shown below. So what I want is indices (1,3),(2,6),(3,7) to be set to one. However, as you can see the entire column is set to one. I can see what it is doing but is there a way to do what I want it to (in an elegant way - no loops).
a=zeros(3,10)
a(1:3,[3 6 7])=1
a =
0 0 1 0 0 1 1 0 0 0
0 0 1 0 0 1 1 0 0 0
0 0 1 0 0 1 1 0 0 0
I realise that you can do something along the lines of
x_idx=1:3, y_idx=[3 6 7];
idx=x_idx*size(a,2)+y_idx;
a(idx)=1;
but just wondering if there was a better, or proper way of doing this in Matlab
You can use sub2ind, which essentially is doing what you have mentioned in your post, but MATLAB has this built-in:
a = zeros(3,10);
a(sub2ind(size(a), 1:3, [3 6 7])) = 1
a =
0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 1 0 0 0
Another way would be to create a logical sparse matrix, then use this to index into a:
a = zeros(3,10);
ind = logical(sparse(1:3, [3 6 7], true, size(a,1), size(a,2)));
a(ind) = 1
a =
0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 1 0 0 0

matlab's imfill function seems bugged?

I need to work with imfill in Matlab (Version 2010b, 7.11.0). I now think there is a bug in the program.
The most simple example that i found here is following: (Fills the Image background (0) beginning at the position [4 3])
BW = [ 0 0 0 0 0 0 0 0;
0 1 1 1 1 1 0 0;
0 1 0 0 0 1 0 0;
0 1 0 0 0 1 0 0;
0 1 0 0 0 1 0 0;
0 1 1 1 1 0 0 0;
0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0];
imfill(BW,[4 3])
According to the specifications this should work IMHO, but I always get following message. Can anyone tell me what I am doing wrong?
??? Error using ==> iptcheckconn at 56
Function IMFILL expected its second input argument, CONN,
to be a valid connectivity specifier.
A nonscalar connectivity specifier must be 3-by-3-by- ...
-by-3.
Error in ==> imfill>parse_inputs at 259
iptcheckconn(conn, mfilename, 'CONN', conn_position);
Error in ==> imfill at 124
[I,locations,conn,do_fillholes] = parse_inputs(varargin{:});
Error in ==> test at 9
imfill(BW,[4 3])
That does not explain the problem but converting BW to a logical array does work. I'm not sure as to why it's like this though:
clear
close all
clc
BW = [ 0 0 0 0 0 0 0 0
0 1 1 1 1 1 0 0
0 1 0 0 0 1 0 0
0 1 0 0 0 1 0 0
0 1 0 0 0 1 0 0
0 1 1 1 1 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0];
BW2 = imfill(logical(BW),[4 3])
BW2 =
0 0 0 0 0 0 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
As you have already seen in the other solution by #Benoit_11, that most probably that input wasn't of logical class, which was throwing an error at you. So, you are set there!
Now, I would like to put forth a tiny bit of bonus suggestion here.
Let's suppose you have a set of seed points with their row and column IDs and you would like to fill an image with those seed points in one go. For that case,
you need to use those IDs as column vectors. Thus, if you have the row and column IDs as -
row_id = [4 3];
col_id = [3 7];
You can fill image with this -
BW = imfill(BW,[row_id(:) col_id(:)])
But, the following code would throw error at you -
BW = imfill(BW,[row_id col_id])

Matlab how to bitwise-AND of a vector and a matrix?

I want to find out the index of the matrix column in which the vector appears. My idea is to do AND of the vector over matrix and only the column that is the same will be 1 in the new vecotr. But I don't know how to do this. Below is example:
H =
0 0 0 0 1 1 1 1 1 1 1 1 0 0 0
0 1 1 1 0 0 0 1 1 1 1 0 1 0 0
1 0 1 1 0 1 1 0 0 1 1 0 0 1 0
1 1 0 1 1 0 1 0 1 0 1 0 0 0 1
S =
0 1 0 1
From that I want to get 2 as second column or even better vector
0 1 0 0 0 0 ... 0
Since there is error in second column.
How can I do this in Matlab or even better Octave?
Not really sure how you tried to approach the problem. But with repmat or bsxfun it is as simple as this:
all(bsxfun(#eq,H,S'))
How about
result = sum(H==repmat(S(:),[1 size(H,2)]))==4;
I found out the function
ismember(H', S, "rows")
works exactly as I want. Your answers are all good too, thanks.
That's pretty easy with broadcasting. The following will require Octave 3.6.0 or later but you can use bsxfun if you have a previous version:
octave-cli-3.8.1> h = logical ([
0 0 0 0 1 1 1 1 1 1 1 1 0 0 0
0 1 1 1 0 0 0 1 1 1 1 0 1 0 0
1 0 1 1 0 1 1 0 0 1 1 0 0 1 0
1 1 0 1 1 0 1 0 1 0 1 0 0 0 1]);
octave-cli-3.8.1> s = logical ([0 1 0 1]');
octave-cli-3.8.1> all (h == s)
ans =
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
From here, it's all a matter of using find to get the column numbers. It will even work if it matches more than 1 column:
octave-cli-3.8.1> find (all (h == s))
ans = 2