Matlab make new array of values without a loop - arrays

In Matlab, I don't know the best way to explain this except for an example. Let's say I have an array called tStart and a tDuration length:
tStart = [3,8,15,20,25];
tDuration = 2;
Is there some way to get a new array such that it would be:
[3,4,5,8,9,10,15,16,17,20,21,22,25,26,27]
So what I want is to use the initial tStart array then make up a new array with the starting value and then next corresponding values for the length of tDuration.
If I do [tStart(1:end)+tDuration] I get an array of ending values, but how can I get the start, end, and all the values in between?
If I [tStart(1:end):tStart(1:end)+tDuration] I get an error.
Any help of a way to do this without a loop would be greatly appreciated.

I would use MATLAB's implicit expansion, reshape, and the ordering of 2d arrays.
First, create a 2d array containing the desired values from tStart:
tStart = [3,8,15,20,25];
tDuration = 2;
tDurAdd = [0:tDuration].'; % numbers to add to tStart
tArray = tStart + tDurAdd;
This gives us
tArray =
3 8 15 20 25
4 9 16 21 26
5 10 17 22 27
These are the correct values, now we just have to reshape them to a row vector:
tResult = reshape(tArray, 1, []);
The final array is:
tResult =
3 4 5 8 9 10 15 16 17 20 21 22 25 26 27
Of course, this can all be done on one line:
tResult = reshape(tStart + [0:tDuration].', 1, []);

Related

Matlab: how do I apply a function along one dimension of an array

I have an array of mxnx4 dimensions and a function with a 4-element vector input. I want to apply my function to give me an mxnx4 output, such that the function is applied mxn times (i.e. the 3rd dimension of my array becomes in the input of my function). Any ideas on how do do this would be massively appreciated. I have looked at arrayfun, but this seems not to address what I want to do. I also want to maintain the formatting of my function as it requires this formatting elsewhere in my code.
I.e.:
F=#(V)[V(1)+V(2);V(2)+V(3); V(3)+V(4); V(4)+V(1)]
to be applied to array M of dimensions 2x3x4 (m=2; n=3)
M = zeros(2,3,4);
M(:,:,1) = [1 2 3;4 5 6];
M(:,:,2) = [7 8 9;10 11 12];
M(:,:,3) = [13 14 15; 16 17 18];
M(:,:,4) = [19 20 21; 22 23 24];
to generate an array of dimensions 2x3x4
C(1,1,:) = F([1 7 13 19])
C(1,2,:) = F([2 8 14 20])
etc.
I can see a for loop would work, applying the following across the mxn matrix
C(m,n,:)=F(M(m,n,:))
However, I need to run this millions of times so would like a faster approach

Delete values between specific ranges of indices in an array

I have an array :
Z = [1 24 3 4 52 66 77 8 21 100 101 120 155];
I have another array:
deletevaluesatindex=[1 3; 6 7;10 12]
I want to delete the values in array Z at indices (1 to 3, 6 to 7, 10 to 12) represented in the array deletevaluesatindex
So the result of Z is:
Z=[4 52 8 21 155];
I tried to use the expression below, but it does not work:
X([deletevaluesatindex])=[]
Another solution using bsxfun and cumsum:
%// create index matrix
idx = bsxfun(#plus , deletevaluesatindex.', [0; 1])
%// create mask
mask = zeros(numel(Z),1);
mask(idx(:)) = (-1).^(0:numel(idx)-1)
%// extract unmasked elements
out = Z(~cumsum(mask))
out = 4 52 8 21 155
This will do it:
rdvi= size(deletevaluesatindex,1); %finding rows of 'deletevaluesatindex'
temp = cell(1,rdvi); %Pre-allocation
for i=1:rdvi
%making a cell array of elements to be removed
temp(i)={deletevaluesatindex(i,1):deletevaluesatindex(i,2)};
end
temp = cell2mat(temp); %Now temp array contains the elements to be removed
Z(temp)=[] % Removing the elements
If you control how deletevaluesatindex is generated, you can instead directly generate the ranges using MATLAB's colon operator and concatenate them together using
deletevaluesatindex=[1:3 6:7 10:12]
then use the expression you suggested
Z([deletevaluesatindex])=[]
If you have to use deletevaluesatindex as it is given, you can generate the concatenated range using a loop or something like this
lo = deletevaluseatindex(:,1)
up = deletevaluseatindex(:,2)
x = cumsum(accumarray(cumsum([1;up(:)-lo(:)+1]),[lo(:);0]-[0;up(:)]-1)+1);
deleteat = x(1:end-1)
Edit: as in comments noted this solution only works in GNU Octave
with bsxfun this is possible:
Z=[1 24 3 4 52 66 77 8 21 100 101 120 155];
deletevaluesatindex = [1 3; 6 7;10 12];
idx = 1:size(deletevaluesatindex ,1);
idx_rm=bsxfun(#(A,B) (A(B):deletevaluesatindex (B,2))',deletevaluesatindex (:,1),idx);
Z(idx_rm(idx_rm ~= 0))=[]

Matlab - replicating arrays values according to occurrences array

For example, A = [19 20 21 22 23 24 25]; B = [2 0 3 0 0 0 2];
How can we get a new array, repeating each value from B accordingly X times?
For example, answer here is: [19 19 21 21 21 25 25].
Please note that I am only allowed to a for loop combined with a repmat call.
If you are only allowed to use repmat and a for loop, you can do the following:
S = [];
for idx = 1 : length(B)
S = [S repmat(A(idx), 1, B(idx))];
end
S is initially a blank array, then for as many values as there are in B (or A since they're both equal in length), simply concatenate S with each value in A that is repeated by the corresponding number in B. S will contain the output.
By running the above example, I get:
S =
19 19 21 21 21 25 25
However, I highly recommend you use more vectorized approaches. I'll leave that to you as an exercise.
Good luck!

Sort and keep index of a n-dimension array -- MATLAB

I have a 12-D array and am using each dimension as an index value in an optimization problem.
A(:,:,i1,i2,i3,i4,i5,i6,i7,i8,i9,i10)
each index value i is a value from 1 to 5.
I want to sort A from greatest to least and keep track of the indices so I know which indices correspond to to what value of A.
So my ideal output would be a 2 column cell/array with one column being the value and the other other column being the index values.
For a simple 3D example: say I have a 3D array: A(:,:,i1).
Where:
A(:,:,1) = 2
A(:,:,2) = 6
A(:,:,3) = 13
A(:,:,4) = 11
A(:,:,5) = 5
I would like my output to be:
13 3
11 4
6 2
5 5
2 1
EDIT:
assume I have 1x1x3x3 sized input such that
A(1,1,1,1) = 3
A(1,1,2,1) = 1
A(1,1,3,1) = 23
A(1,1,1,2) = 12
A(1,1,2,2) = 9
A(1,1,3,2) = 8
A(1,1,1,3) = 33
A(1,1,2,3) = 14
A(1,1,3,3) = 6
the expected output would be:
33 [1,1,1,3]
23 [1,1,3,1]
14 [1,1,2,3]
12 [1,1,1,2]
9 [1,1,2,2]
8 [1,1,3,2]
6 [1,1,3,3]
3 [1,1,1,1]
1 [1,1,2,1]
This should be a generic code for any multi-dimensional input array -
%// Sort A and get the indices
[sorted_vals,sorted_idx] = sort(A(:),'descend');
%// Set storage for indices as a cell array and then store sorted indices into it
c = cell([1 numel(size(A))]);
[c{:}] = ind2sub(size(A),sorted_idx);
%// Convert c to the requested format and concatenate with cell arary version of
%// sorted values for the desired output
out = [num2cell(sorted_vals) mat2cell([c{:}],ones(1,numel(A)),numel(size(A)))];
The generic code owes its gratitude to this fine solution.
I guess this is what you want:
b=A(:);
[sorted_b,ind]=sort(b,'descend');
[dim1,dim2,dim3,dim4]=ind2sub(size(A),ind);
%arranging in the form you want
yourCell=cell(size(b,1),2);
yourCell(:,1)=mat2cell(sorted_b,ones(size(b,1),1),1);
%arranging indices -> maybe vectorized way is there for putting values in "yourCell"
for i=1:size(b,1)
yourCell{i,2}=[dim1(i) dim2(i) dim3(i) dim4(i)];
end
For the array A, given by you, my output looks like:
33 [1,1,1,3]
23 [1,1,3,1]
14 [1,1,2,3]
12 [1,1,1,2]
9 [1,1,2,2]
8 [1,1,3,2]
6 [1,1,3,3]
3 [1,1,1,1]
1 [1,1,2,1]
which matches with your output.

calculation of value from given matrix

suppose that we have following array :
a=[12 21 23 10 34 54 10 9 5 6 7 8]
a =
12 21 23 10 34 54 10 9 5 6 7 8
length(a)=
length(a)
ans =
12
now i want to create following vector b ,which b(1),b(2)...b(6) are following
b(1)=sqrt(a(1)^2+a(2)^2)
b(2)=sqrt(a(3)^2+a(4)^2)
b(3)=sqrt(a(5)^2+a(6)^2))
b(4)=sqrt(a(7)^2+a(8)^2)
b(5)=sqrt(a(9)^2+a(10)^2))
b(6)=sqrt(a(11)^2+a(12)^2)
i have wrote following code
or i=2:2:length(a)
b(i/2)=sqrt(a(i-1)^2+a(i)^2);
end
>> b
b =
24.1868 25.0799 63.8122 13.4536 7.8102 10.6301
but i am not sure if it is correct,pleas help me to clarify if everything is ok in my code
In matlab, loops are quite slow. Using vectors is much faster. I suggest therefore a solution without a loop:
a_1 = a(1:2:end);
a_2 = a(2:2:end);
b = sqrt(a_1.^2 + a_2.^2);
first, you create a vector a_1 containing all elements with odd indices of a and a vector a_2 containing all elements with even indices.
Then you square them element wise (.^) and take the square of the sum.
For you example of a, this is 75 times faster. As you increase the size of the array, you will save even more time.

Resources