In MATLAB is there a way to define a variable say runningValue and push values onto it in succession an unknown number of times?
What I have been doing is something like this:
runningValue = 0;
for j=1:length(someVector)
...
runningValue(end+1) = (some value);
...
endfor
But this forces a leading 0. I know that after all is done I could just put j(1) = []; but I was wondering if there is a more elegant way to do this.
Note that the length of the runningValue variable is not a priori known; in particular, we are not populating length(someVector) elements, referring to the pseudocode above, and the j index is no of use.
Aside from initializing runningValue to empty, you might as well try reducing the number of appendition, which is an O(n) operation. Instead of appending an element on every loop, you can double the size of the array when it is full. This way, you reduce the number of appendition from n to log(n):
runningValue = [];
len = 0;
for j = 1:n
if (j > len)
runningValue = [runningValue zeros(size(runningValue))];
len = length(runningValue);
end
runningValue(j) = (some value);
end
runningValue(j+1:len) = []; % If you need to remove the extra zeros
You can simply construct a new vector using an existing vector plus another element:
runningValue = [];
for j=1:5
runningValue = [runningValue i]; % i can be the element you want to append to the vector
end
This code will output:
runningValue =
1 2 3 4 5
Related
I am currently using a nested 'for' loop to calculate an average value. This is an image with 3527*256 pixels, each pixel containing 448 values. I wish to multiply these 448 values with the array called 'modis_rsr'(448*8), then sum only the zero and positive values. After that, I wish to divide this sum by the sum of the values of 'modis_rsr' corresponding to only those with positive values in hyp_1nm.
As you would expect, this sequence is taking too long, and I wish to use a matrix multiplication to speed things up. The only thing I don't know how to do is to include the conditional sum for 'modis_rsr'. I was thinking of creating a reference array to store the indices of those which were negative. But that also seems computationally intensive.
for j = 1:8
for k = 1:256
for i = 1:3527
RLs = 0;
for jj = 1:448
if hyp_1nm(i,jj,k)>= 0
RLi = hyp_1nm(i,jj,k)*modis_rsr(jj,j);
RLs = RLs + RLi;
temp_rsr(jj,j) = modis_rsr(jj,j);
else
temp_rsr(jj,j) = 0;
end
end
Rs = sum(temp_rsr(1:448,j));
% Write basr
basr(i,j,k) = RLs/Rs;
end
end
end
You can't multiply arrays along one particular dimension with matlab, so you can't avoid using loop in this case. But you can reduce the number of loop by using the logical indexing and the element-wise multiplication.
for j = 1:8
for k = 1:256
for i = 1:3527
RLs = 0;
ind = hyp_1nm(i,:,k) >= 0; %by using the logical indexing you can avoid 1 loop.
RLs = sum(hyp_1nm(i,ind,k).*modis_rsr(ind,j)'); % .* = element-wise multiplication
temp_rsr(ind,j) = modis_rsr(ind,j);
temp_rsr(~ind,j) = 0;
Rs = sum(temp_rsr(1:448,j));
basr(i,j,k) = RLs/Rs;
end
end
end
If really you want to avoid for loop, you can use the function bsxfun, but bsxfunonly hide the foor loop, it don't linearize your code.
I have several matrices <1x1000> containing integers such as:
matrix = [0,0,0,0,0,30,30,30,40,40,50,50,50,40,0,0,0,30,30,30]
I want to print (disp, and later plot) them like this: 30,40,50,40,30. Basically ignore the duplicates if they come after each other.
Another example:
matrix = [0,0,0,0,10,10,10,10,50,50,50,50,10,10,10,50,50] shall give: 10,50,10,50
Help is very much appreciated!
Use this:
[~,c]=find([NaN diff(matrix)]);
output=matrix(c);
output = output(output~=0)
and to plot the output, simply use: plot(output)
Result = 0;
% loop over all nonzero values in matrix
for Element = matrix
if Element == Result(end)
% skip if equal
continue
else
% add new value
Result(end+1) = Element;
end
end
% discard zero entries
Result = Result(Result ~= 0);
All solutions provided so far use either loops or the function find which are both inefficient.
Just use matrix indexation:
[matrix((matrix(1:end-1)-matrix(2:end))~=0), matrix(end)]
ans =
0 30 40 50 40 0 30
By the way in your example are you discarting the 0s even if they come in repeated sequences?
Lets call the output matrix um then
um(1) = matrix(1);
j = 1;
for i=2: length(matrix)
% Ignore repeating numbers
if (um(j) ~= matrix(i))
j = j + 1;
um(j) = matrix(i);
end
end
% Remove zeros
um = um(um~=0);
I want to create a struct with a field that the number of elements changes according to the value of n to be n(n-1)/2.
E.g., if n=4, s=struct('name', { {1,2}, {1,3}, {1,4}, {2,3}, {2,4}, {3,4} }).
I wrote this code but it generates only the last values of the loop:
function [ b ] = Bwcl( cl )
n=size(cl,1);
for k=1:n-1
for i=k:n-1
b(k).name={num2str(k),num2str(i+1)};
end
end
DomDev answered the question correctly. However, I'd like to show you a way without loops:
n = 4;
ind = nchoosek(1:n, 2);
D = num2cell(ind, 2);
s = struct('name', D);
The second line of code uses nchoosek to find all unique combinations of pairs from 1 up to n. This produces a matrix where each row is a unique pair of values. We then transform this into a cell array using num2cell where each pair of values occupies one cell in the cell array, such as how you have presented it above. We then feed this cell array into struct to produce the final desired structure.
If you prefer a one-liner (two if you count declaring n):
n = 4;
s = struct('name', num2cell(nchoosek(1:n, 2), 2));
You forgot a counter to your code. The problem was the b(k), which rewrote at the same location multiple times. With b(counter) shown below, it works.
counter = 0;
n=size(cl,1);
for k=1:n-1
for i=k:n-1
counter = counter + 1;
b(counter).name={num2str(k),num2str(i+1)};
end
end
I need to use vectorization to remove the nested while loop inside my for loop, for making an insertion sort program. I am not allowed to have a while loop inside my for loop, I must do it "such that there are no while or for loops in your function except the outermost for loop."
Here is the code I have currently
function insertsort(array)
array = [2 1 3 2 1]
for i = 2:length(array)
value = array(i);
j = i - 1;
while (j >= 1) && (array(j) > value)
array(j+1) = array(j);
j = j-1;
end
array(j+1) = value;
end %forLoop
disp(array);
end %insertionSort
This will do it:
array = [2 1 3 2 1]
for i = 2:length(array)
value = array(i);
j = i - 1;
array_j=array(1:j);
array_j_indices=cumsum(array_j>value);
[~,n]=find(array_j_indices==1);
newArray=array;
array(n+1:i)=array_j(array_j>value);
j=j-max(array_j_indices);
array(j+1) = value;
end %forLoop
disp(array);
Explanation: First take elements from j to 1 in an array, since while loop will eventually scan through those elements. Find which of the elements are greater than the value and take its cumulative sum which will tell us how many elements are greater than the value. Because that is the amount we have to decrement j by. Now, find where the first 1 occurs (i.e. the first index at which the number is greater than value, since we have to shift every element to the right by 1 position from that index). After that, decrement j and put the value back. You are done.
Is there a reason you don't want to use the built in sort ?
ans=sort(array)
will do it.
I'm trying to shift all the elements of an array to the left, so that the first element would become the last element, the second becomes the first, the third the second, etc. I know about the circshift commands, but I would like to do this using a for loop.
Here's what I did.
old=[]
n=length(old)
for i=1;i<(n-1);i=i+1;
for j=2;j<n;j=j+1;
new(j)=old(i)
end
end
But it of course didn't work. I'm having trouble figuring out to make an array of n elements, without specifying n, which is why I used old=[], but I think that created an array of 0 elements.
How can I make this code work?
If you want to avoid specifying the n length of the array, you have to give it as an input argument in a function.
For example you can do something like this:
function new = shiftLeft(old)
n = length(old);
for i =1:n
new(i) = old(mod(i,n)+1);
end
return
So with this one, if you have an array for example old = [1 2 3 4]; you can will get something like new = [2 3 4 1];
mod(a,b) is the modulo operator, you can find more information if you type help mod.
So your irst step is to learn how to specify a for loop in Matlab, what you have is like C syntax. This is not Matlab syntax at all.
The following is how to do it using forloops but this is not good matlab programming. You could easily do it without loops too.
vec = 1:10;
temp = [];
shiftby = 2;
for ii = 1:shiftby %Each iteration shifts by one
temp = vec(end); %Store the last element of vec
for jj = size(vec, 2):-1:2; %inner loop must shift each element from the end to element 2
vec(jj) = vec(jj-1);
end
vec(1) = temp; %put the old end value at the beginning
end
but you could also just do this which is a much more Matlabesque way to code it:
vec = [vec(end - shiftby + 1: end), vec(1:end - shiftby)]