I have a vector with 4225 elements that its elements are separated by spaces and I have to use this vector in MuPAD as edge weight matrix of a directed graph. In order to make this vector accessible in MuPAD as a graph edge weight matrix, its elements should be separated by commas. Since the number of elements is huge, it's a waste of time to write commas between them one by one. So is there any simple way to do this in matlab?
Big thanks in advance
This ought to do the trick:
%// example vector
a = [4 5 6 7 8 9 10 11 12 13];
%// replace all consecutive spaces with a comma
aCSV = regexprep(num2str(a,17), '\s*', ',')
Output:
aCSV =
4,5,6,7,8,9,10,11,12,13
Here's a version using only sprintf:
v = [1 2 exp(1) 3 pi 4 5 realmax];
s = sprintf('%.17g,',v); % Up to 17 decimal places (double precision has about 16)
s = s(1:end-1); % Remove trailing comma
This returns
s =
1,2,2.7182818284590455,3,3.1415926535897931,4,5,1.7976931348623157e+308
See this article for details on using format strings with sprintf if you wish to further customize this.
Related
Below is the sample code that describe my issue.
ff= [{'1 2 3 4 5'};{'2 2 3 4 2'};{'3 2 3 4 3'};{'4 2 3 4 4'}];
YY=[];
for i=1:length(ff)
xx=str2num(ff{i,1});
YY=[YY;xx];
end
similar to the sample code my real length of ff length is very large and it is taking longer to finish the conversion. is there a way to make it faster?
Your solution is going to be particularly slow since you keep expanding the size of YY every time through the for loop.
To optimize this, you could first convert your cell array of strings into one long string using strjoin. Then you can apply str2num to this entire string at once and reshape the result.
YY = reshape(str2num(strjoin(ff)), [], numel(ff)).'
% 1 2 3 4 5
% 2 2 3 4 2
% 3 2 3 4 3
% 4 2 3 4 4
If your version of MATLAB doesn't have strjoin, you can always replace it with sprintf
YY = reshape(str2num(sprintf('%s ', ff{:})), [], numel(ff)).';
Another option would be to convert each entry of the cell array to numbers using cellfun and num2str and then concatenate the result along the first dimension.
values = cellfun(#num2str, ff, 'UniformOutput', false);
YY = cat(1, values{:});
The first option is about twice as fast since you call num2str only once and the memory needed to store the temporary string created by strjoin is going to be less than the space required to store the same data as a numeric datatype (double).
Suppose that I have a Q vector which is defined as Q = [1 2 3 4 5 8 9 10 15]; and I would like to find a way to extract different vectors of consecutive numbers and also a vector for the rest of the elements. So my result would be like:
q1 = [1 2 3 4 5];
q2 = [8 9 10 ];
q3 = [15];
You can do this using diff, cumsum and accumarray:
q = accumarray(cumsum([1, diff(Q)~=1])', Q', [], #(x){x})
which returns:
{[1,2,3,4,5];
[8,9,10];
[15]}
i.e. q{1} gives you [1,2,3,4,5] etc which is a far cleaner solution to having separately named vectors. But if you really really wanted to have them, and you know exactly how many groups you will get out, you can do it as follows:
[q1,q2,q3] = q{:};
Explanation:
accumarray will apply an aggregation function (4th input) to elements of a vector (2nd input) based on groupings specified in another vector (1st input).
To use the notation in the docs:
sub = cumsum([1, diff(Q)~=1])';
val = Q';
fun = #(x){x};
Note that sub needs to start from 1. The idea is to use diff to find elements that are consecutive (i.e. where Q(i+1) - Q(i) == 1) which is vectorized using the diff function. By specifying diff(Q)~=1 we can find the breaks between groups of consecutive numbers (concatenating the 1 at the beginning to force a break at the start). cumsum then just converts these breaks into vector of in the right form for sub i.e.
sub = [1 1 1 1 1 2 2 2 3]
The aggregation function we specify is just cell concatenation.
I would like to create a column vector from the elements of a matrix A of size (3,3) that are not on the diagonal. Thus, I would have 6 elements in that output vector. How can I do this?
Use eye and logical negation, although this is no better than Divakar's original answer, and possibly significantly slower for very large matrices.
>> A = magic(4)
A =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
>> A(~eye(size(A)))
ans =
5
9
4
2
7
14
3
10
15
13
8
12
Use this to get such a column vector, assuming A is the input matrix -
column_vector = A(eye(size(A))==0)
If you don't care about the order of the elements in the output, you can also use a combination of setdiff and diag -
column_vector = setdiff(A,diag(A))
You can also use linear indexing to access the diagonal elements and null them. This will automatically reshape itself to a single vector:
A(1:size(A,1)+1:end) = [];
Bear in mind that this will mutate the original matrix A. If you don't want this to happen, make a copy of your matrix then perform the above operation on that copy. In other words:
Acopy = A;
Acopy(1:size(A,1)+1:end) = [];
Acopy will contain the final result. You need to create a vector starting from 1 and going to the end in increments of the rows of the matrix A added with 1 due to the fact that linear indices are column-major, so the linear indices used to access a matrix progress down each row first for a particular column. size(A,1) will allow us to offset by each column and we add 1 each time to ensure we get the diagonal coefficient for each column in the matrix.
Assuming that the matrix is square,
v = A(mod(0:numel(A)-1, size(A,1)+1) > 0).';
I have a matrix S something like:
1 4 7
2 5 8
3 6 9
Then I make a=complex(S{2},S{3}) and wanted to find the abs(a);. This is not possible in MATLAB as a is not an integer - it is a matrix. How can I get the magnitude of each row of matrix a?
PS: the matrix is read from a text file using textscan() as S = textscan(fileID,'%d %d %d', 'delimiter','\t');.
Second question:
Assuming again hav the following S matrix.
1 4 7 2 1
2 5 8 3 4
3 6 9 6 8
Now I wanted to arrange them in such way that column 2,3 and 4,5 alternate like this:
4 2
7 1
5 3
8 4
6 6
9 8
How can I do that without using a loop?
Thanks.
Going with my assumption in the comments, I'm going to assume that the second column consists of your real component of your matrix while the third column consists of your imaginary components. Your matrix S is actually a cell array of elements. You don't need to use complex then abs. You can simply take each of the columns, individually square them, add them together and take the square root. What I would do is convert the cell array into a 2D matrix, cast it to double to allow for floating point precision when finding the magnitude, and do what I just did above. This is necessary because abs and sqrt will only work for floating-point numbers. Your elements in S are already int32 due to the %d delimiter from textread. In other words:
Smat = double(cell2mat(S));
realComp = Smat(:,2);
imagComp = Smat(:,3);
mag = sqrt(realComp.^2 + imagComp.^2);
mag will thus return the magnitude of each row for you, assuming that the second column is the real component and the third component is the imaginary component as we specified.
However, if you're dead set on using complex and abs, you can do it like so:
Smat = double(cell2mat(S));
imagNumbers = complex(Smat(:,2), Smat(:,3));
mag = abs(imagNumbers);
This should still give you the same results as we talked about above.
Edit
Seeing your edit in your post above, we can achieve that quite easily by subsetting the matrix, then applying reshape to each part of the matrix you want. In other words:
Smat = double(cell2mat(S));
realMat = Smat(:,2:3); %// Grab second and third columns
imagMat = Smat(:,4:5); %// Grab fourth and fifth columns
realCol = reshape(realMat.', [], 1); % // Form the columns like you specified
imagCol = reshape(imagMat.', [], 1);
finalMatrix = [realCol imagCol];
finalMatrix should contain those two columns that you specified above in a single matrix.
I have two vectors, idx1 and idx2, and I want to obtain the values between them. If idx1 and idx2 were numbers and not vectors, I could do that the following way:
idx1=1;
idx2=5;
values=idx1:idx2
% Result
% values =
%
% 1 2 3 4 5
But in my case, idx1 and idx2 are vectors of variable length. For example, for length=2:
idx1=[5,9];
idx2=[9 11];
Can I use the colon operator to directly obtain the values in between? This is, something similar to the following:
values = [5 6 7 8 9 9 10 11]
I know I can do idx1(1):idx2(1) and idx1(2):idx2(2), this is, extract the values for each column separately, so if there is no other solution, I can do this with a for-loop, but maybe Matlab can do this more easily.
Your sample output is not legal. A matrix cannot have rows of different length. What you can do is create a cell array using arrayfun:
values = arrayfun(#colon, idx1, idx2, 'Uniform', false)
To convert the resulting cell array into a vector, you can use cell2mat:
values = cell2mat(values);
Alternatively, if all vectors in the resulting cell array have the same length, you can construct an output matrix as follows:
values = vertcat(values{:});
Try taking the union of the sets. Given the values of idx1 and idx2 you supplied, run
values = union(idx1(1):idx1(2), idx2(1):idx2(2));
Which will yield a vector with the values [5 6 7 8 9 10 11], as desired.
I couldn't get #Eitan's solution to work, apparently you need to specify parameters to colon. The small modification that follows got it working on my R2010b version:
step = 1;
idx1 = [5, 9];
idx2 = [9, 11];
values = arrayfun(#(x,y)colon(x, step, y), idx1, idx2, 'UniformOutput', false);
values=vertcat(cell2mat(values));
Note that step = 1 is actually the default value in colon, and Uniform can be used in place of UniformOutput, but I've included these for the sake of completeness.
There is a great blog post by Loren called Vectorizing the Notion of Colon (:). It includes an answer that is about 5 times faster (for large arrays) than using arrayfun or a for-loop and is similar to run-length-decoding:
The idea is to expand the colon sequences out. I know the lengths of
each sequence so I know the starting points in the output array. Fill
the values after the start values with 1s. Then I figure out how much
to jump from the end of one sequence to the beginning of the next one.
If there are repeated start values, the jumps might be negative. Once
this array is filled, the output is simply the cumulative sum or
cumsum of the sequence.
function x = coloncatrld(start, stop)
% COLONCAT Concatenate colon expressions
% X = COLONCAT(START,STOP) returns a vector containing the values
% [START(1):STOP(1) START(2):STOP(2) START(END):STOP(END)].
% Based on Peter Acklam's code for run length decoding.
len = stop - start + 1;
% keep only sequences whose length is positive
pos = len > 0;
start = start(pos);
stop = stop(pos);
len = len(pos);
if isempty(len)
x = [];
return;
end
% expand out the colon expressions
endlocs = cumsum(len);
incr = ones(1, endlocs(end));
jumps = start(2:end) - stop(1:end-1);
incr(endlocs(1:end-1)+1) = jumps;
incr(1) = start(1);
x = cumsum(incr);