How to split vector by zeros in MATLAB - matlab

I have got a problem with splitting a vector by zeros.
I have a vector for example
v=[1 3 2 6 4 0 0 2 4 6 0 0 0 3 1]
I need to get vectors like
v1=[1 3 2 6 4]
v2=[2 4 6]
v3=[3 1]
Is there any way to do this by using MATLAB functions?
Of course I don't know of how many subvectors are included in main vector v and how many zeros delimits vectors.
I'm not a programmer and also I'm not a pro in MATLAB.
I know a procedural way to do this but want do it by MATLAB somehow.
I found a function A = strsplit(str,delimiter) but I don't have string I have a vector.
So I searched for conversion function. I found S = char(V) but when I executed it it crashed.

It's better to have the output as a cell array, not as separate variables. That way the output will be easier to handle.
Try this:
v = [1 3 2 6 4 0 0 2 4 6 0 0 0 3 1]; %// data
w = [false v~=0 false]; %// "close" v with zeros, and transform to logical
starts = find(w(2:end) & ~w(1:end-1)); %// find starts of runs of non-zeros
ends = find(~w(2:end) & w(1:end-1))-1; %// find ends of runs of non-zeros
result = arrayfun(#(s,e) v(s:e), starts, ends, 'uniformout', false); %// build result
Result (for your example):
>> result{:}
ans =
1 3 2 6 4
ans =
2 4 6
ans =
3 1

The strsplit() solution for a vector of whole numbers smaller than 9 (so a very specific solution, for a general solution see Luis Mendo's). Split and convert back to number:
res = strsplit(char(v), char(0));
res = cellfun(#(x) x - 0,res,'un',0);
celldisp(res)
res{1} =
1 3 2 6 4
res{2} =
2 4 6
res{3} =
3 1

Related

Convert 3d matrix to String and back to 3d matrix using Matlab

I am currently working on a stenography assignment on how to embed secret image to a cover image using Wang's algorithm. Basically i just want to change for eg:
3d matrix
A(:,:,1) = [5 7 8; 0 1 9; 4 3 6];
A(:,:,2) = [1 0 4; 3 5 6; 9 8 7];
A(:,:,3) = [7 9 3; 4 5 9; 1 9 9];
To
Str = '578019436104356987793459199'
and also vice-versa if anybody can help out.
Another way is to just use sprintf. You first need to transpose each slice independently, so the call to permute as per Ander's answer will get to that point. After you can just supply a single format string of %d (integer) and the actual permuted matrix and it will unroll all elements column-wise and concatenate all of the numbers together. The additional advantage is that you no longer need to assume that only one digit occupies each matrix element:
str = sprintf('%d', permute(A, [2 1 3]));
Example
>> str = sprintf('%d', permute(A, [2 1 3]))
str =
578019436104356987793459199
>> class(str)
ans =
char
However, to reconstruct the matrix, you will have to assume that there's one element per matrix. In this case, you could use the undocumented sprintfc function that can output one cell per character, then convert the characters to numbers with str2double. Finally, reshape your matrix and undo the transpose:
A2 = permute(reshape(str2double(sprintfc('%c', str)), size(A)), [2 1 3]);
Example
>> A2 = permute(reshape(str2double(sprintfc('%c', str)), size(A)), [2 1 3])
A2(:,:,1) =
5 7 8
0 1 9
4 3 6
A2(:,:,2) =
1 0 4
3 5 6
9 8 7
A2(:,:,3) =
7 9 3
4 5 9
1 9 9
Because of the order of the unrolling of MATLAB matrices, your problem is slightly less straightforward than it may seem. You need to use reshape and permute to make it work.
str=arrayfun(#num2str,reshape(permute(A,[2 1 3]),[],1,1)).';
A2=permute(reshape(arrayfun(#str2double,str),[size(A)]),[2 1 3]);
isequal(A2,A)
This of course assumes what #Sardar comments in your question: all numbers have single digits (i.e. are integers range 0-9)

Create Non Zero elements of Matrix in vector form in Matlab

I have a Matrix of size M by N in which each row has some zero entries. I want to create M row vectors such that each of the vector contains the non zero elements of each row. For example if I have the following Matrix
A=[0 0 0 5;0 0 4 6;0 1 2 3;9 10 2 3]
I want four different row vectors of the following form
[5]
[4 6]
[1 2 3]
[9 10 2 3]
This can be done with accumarray using an anonymous function as fourth input argument. To make sure that the results are in the same order as in A, the grouping values used as first input should be sorted. This requires using (a linearized version of) A transposed as second input.
ind = repmat((1:size(A,2)).',1,size(A,2)).';
B = A.';
result = accumarray(ind(:), B(:), [], #(x){nonzeros(x).'});
With A = [0 0 0 5; 0 0 4 6; 0 1 2 3; 9 10 2 3]; this gives
result{1} =
5
result{2} =
4 6
result{3} =
1 2 3
result{4} =
9 10 2 3
Since Matlab doesn't support non-rectangular double arrays, you'll want to settle on a cell array. One quick way to get the desired output is to combine arrayfun with logical indexing:
nonZeroVectors = arrayfun(#(k) A(k,A(k,:)~=0),1:size(A,1),'UniformOutput',false);
I used the ('UniformOutput',false) name-value pair for the reasons indicated in the documentation (I'll note that the pair ('uni',0) also works, but I prefer verbosity). This input produces a cell array with the entries
>> nonZerosVectors{:}
ans =
5
ans =
4 6
ans =
1 2 3
ans =
9 10 2 3

Matlab, How to get each column in a matrix

I got a 4-by-n matrix, like
A =
1 5 9
3 0 6
2 3 10
7 8 4
What I want to do with A is getting each half column of A as
Line1Point1 = [1 3]
Line1Point2 = [2 7]
Line2Point1 = [5 0]
Line2Point2 = [3 8]
Line3Point1 = [9 6]
Line3Point2 = [10 4]
How could I do that? I’m pretty new to matlab coding.. Any help is really appreciated..
Cheers
Use reshape function, for example:
>> A = [1 5 9;
3 0 6;
2 3 10;
7 8 4];
>> reshape(A,2,6)
ans =
1 2 5 3 9 10
3 7 0 8 6 4
Storing such information as many variables is generally a bad idea
Some options for storing and accessing are
Cell array
Line=mat2cell(A,[2,2],ones(1,size(A,2))).'
access with
Line{2,1}
ans =
5
0
Indexing
as other answers
Anonymous Function
Line=#(l,p)A(2*p-1:2*p,l)
access with
Line(2,1)
ans =
5
0
Structure
Not really a useful solution, more for interests sake
for ii=1:size(A,2);for jj=1:2;Line(ii).Point(jj).Value=A(2*jj-1:2*jj,ii);end;end
access with
Line(2).Point(1).Value
ans =
5
0
A(1:2,1) will give you first half of the first column.
A(3:4,1) will give you second half of the first column.
A(1:2,2) will give you first half of the second column.
A(3:4,2) will give you second half of the second column.
A(1:2,3) will give you first half of the third column.
A(3:4,3) will give you second half of the third column.
You can create the variables with the eval function, which executes the input string. Using eval is commonly regarded as bad practice since it is horrible to debug.
Nevertheless, here's the code:
A = [1 5 9; 3 0 6; 2 3 10; 7 8 4];
for ii = 1:length(A(1,:))
eval(['Line' num2str(ii) 'Point1 = A(1:2, ii)' ]);
eval(['Line' num2str(ii) 'Point2 = A(3:4, ii)' ]);
end
% Now all variables are created - for example: Line2Point1
A more elegant solution could be to store the vectors in a cell array. You can acces the first vectors for example by typing: c{1,1}
c = cell(length(A(1,:)),2)
for ii = 1:length(A(1,:))
c{ii,1} = A(1:2, ii);
c{ii,2} = A(3:4, ii);
end
I would suggest using 3D arrays to store and then access those values.
Code
N = size(A,1)/2;
LinePoint = permute(reshape(A,N,size(A,1)/N,[]),[1 3 2])
Here,
2nd dimension indices (columns) would represent Line IDs
3rd dimension indices would represent Point IDs.
Thus, the representative 3D array would be - LinePoint(:,LineID,PointID).
Example run
For your given A, we would have LinePoint as -
LinePoint(:,:,1) =
1 5 9
3 0 6
LinePoint(:,:,2) =
2 3 10
7 8 4
Thus,
Line1Point1 would be denoted by LinePoint(:,1,1)
Line1Point2 would be denoted by LinePoint(:,1,2)
Line2Point1 would be denoted by LinePoint(:,2,1)
Line2Point2 would be denoted by LinePoint(:,2,2)
Line3Point1 would be denoted by LinePoint(:,3,1)
Line3Point2 would be denoted by LinePoint(:,3,2)

matlab indexing with multiple condition

I can't figure out how to create a vector based on condition on more than one other vectors. I have three vectors and I need values of one vector if values on other vectors comply to condition.
As an example below I would like to choose values from vector a if values on vector b==2 and values on vector c==0 obviously I expect [2 4]
a = [1 2 3 4 5 6 7 8 9 10];
b = [1 2 1 2 1 2 1 2 1 2];
c = [0 0 0 0 0 1 1 1 1 1]
I thought something like:
d = a(b==2) & a(c==0)
but I have d = 1 1 1 1 1 not sure why.
It seems to be basic problem but I can find solution for it.
In your case you can consider using a(b==2 & c==0)
Use ismember to find the matching indices along the rows after concatenating b and c and then index to a.
Code
a(ismember([b;c]',[2 0],'rows'))
Output
ans =
2
4
You may use bsxfun too for the same result -
a(all(bsxfun(#eq,[b;c],[2 0]'),1))
Or you may just tweak your method to get the correct result -
a(b==2 & c==0)

MATLAB Concatenate matrices with unequal dimensions

Is there any easy way to concatenate matrices with unequal dimensions using zero padding?
short = [1 2 3]';
long = [4 5 6 7]';
desiredResult = horzcat(short, long);
I would like something like:
desiredResult =
1 4
2 5
3 6
0 7
Matrices in MATLAB are automatically grown and padded with zeroes when you assign to indices outside the current bounds of the matrix. For example:
>> short = [1 2 3]';
>> long = [4 5 6 7]';
>> desiredResult(1:numel(short),1) = short; %# Add short to column 1
>> desiredResult(1:numel(long),2) = long; %# Add long to column 2
>> desiredResult
desiredResult =
1 4
2 5
3 6
0 7
EDIT:
I have edited my earlier solution so that you won't have to supply a maxLength parameter to the function. The function calculates it before doing the padding.
function out=joinUnevenVectors(varargin)
%#Horizontally catenate multiple column vectors by appending zeros
%#at the ends of the shorter vectors
%#
%#SYNTAX: out = joinUnevenVectors(vec1, vec2, ... , vecN)
maxLength=max(cellfun(#numel,varargin));
out=cell2mat(cellfun(#(x)cat(1,x,zeros(maxLength-length(x),1)),varargin,'UniformOutput',false));
The convenience of having it as a function is that you can easily join multiple uneven vectors in a single line as joinUnevenVectors(vec1,vec2,vec3,vec4) and so on, without having to manually enter it in each line.
EXAMPLE:
short = [1 2 3]';
long = [4 5 6 7]';
joinUnevenVectors(short,long)
ans =
1 4
2 5
3 6
0 7
Matlab automatically does padding when writing to a non-existent element of a matrix.
Therefore, another very simple way of doing this is the following:
short=[1;2;3];
long=[4;5;6;7];
short(1:length(long),2)=long;