increment fields values of struct in matlab - matlab

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

Related

cellfun with two arrays of indices

I have one big cell with N by 1 dimension. Each row is either a string or a double. A string is a variable name and the sequential doubles are its values until the next string (another variable name). For example:
data = {
var_name1;
val1;
val2;
val3;
val4;
val5;
var_name2;
val1;
val2;
var_name3;
val1;
val2;
val3;
val4;
val5;
val6;
val7}
and so on. I want to separate the data cell into three cells; {var_name and it's 5 values}, {var_name and it's 2 values}, {var_name and it's 7 values}. I try not to loop as much as possible and have found that vectorization along with cellfun works really well. Is it possible? The data cell has close to million rows.
I believe the following should do what you're after. The main pieces are to use cumsum to work out which name each row corresponds to, and then accumarray to build up lists per name.
% Make some data
data = {'a'; 1; 2; 3;
'b'; 4; 5;
'c'; 6; 7; 8; 9;
'd';
'e'; 10; 11; 12};
% Which elements are the names?
isName = cellfun(#ischar, data);
% Use CUMSUM to work out for each row, which name it corresponds to
whichName = cumsum(isName);
% Pick out only the values from 'data', and filter 'whichName'
% for just the values
justVals = data(~isName);
whichName = whichName(~isName);
% Use ACCUMARRAY to build up lists per name. Note that the function
% used by ACCUMARRAY must return something scalar from a column of
% values, so we return a scalar cell containing a row-vector
% of those values
listPerName = accumarray(whichName, cell2mat(justVals), [], #(x) {x.'});
% All that remains is to prepend the name to each cell. This ends
% up with each row of output being a cell like {'a', [1 2 3]}.
% It's simple to make the output be {'a', 1, 2, 3} by adding
% a call to NUM2CELL on 'v' in the anonymous function.
nameAndVals = cellfun(#(n, v) [{n}, v], data(isName), listPerName, ...
'UniformOutput', false);
cellfun is for applying a function to each element of a cell.
When you pass multiple arguments to cellfun like that, it takes the ith argument of data, indx_first, and indx_last, and uses each of them in the anonymous function. Substituting those variables in, your function evaluates to x(y : z), for each element x in data. In other words, you're doing data{i}(y : z), i.e., indexing the actual elements of the cell array, rather than indexing the cell array itself. I don't think that's what you want. Really you want data{y : z}, for each (y, z) pair given by corresponding elements in indx_first and indx_last, right?
If that's indeed the case, I don't see a vectorized way to solve your problem, because each of the "variables" has different size. But you do know how many variables you have, which is the size of indx_first. So I'd pre-allocate and then loop, like so:
>> vars = cell(length(indx_first), 2);
>> for i = 1:length(vars)
vars{i, 1} = data{indx_first(i) - 1}; % store variable name in first column
vars{i, 2} = [data{indx_first(i) : indx_last(i)}]; % store data in last column
end
At the end of this, you'll have a cell array with 2 columns. The first column in each row is the name of the variable. The second is the actual data. I.e.
{'var_name1', [val1 val2 val3 val4 val5];
'var_name2', [val1 val2];
.
.
.

Generate random 2D matrix with unique rows in octave/matlab

I want to generate a 2D matrix(1000x3) with random values in the range of 1 to 10 in octave. Using randi(10,1000,3) will generate a matrix with repeated row values. But I want to generate unique(unrepeated) rows. Is there any way that, I can do that?
You can do that easily by getting the cartesian product to create all possibilities and shuffle the array as follows. To create the cartesian product, you will need my custom cartprod.m function that generates a cartesian product.
C = cartprod(1:10,1:10,1:10);
The following line then shuffles the cartesian product C.
S = C(randperm( size(C,1) ),:);
Notes:
Every row in S is unique and you can verify that size( unique( S ) ) == 1000.
I should note that this code works on Matlab 2015a. I haven't tested it in Octave, which is what OP seems to be using. I've been told the syntax is pretty much identical though.
You can generate all possible three-item sequences drawn from 1 through 10, with replacement, using the following function:
function result = nchoosek_replacement(n, k)
%// Edge cases: just return an empty matrix
if k < 1 || n < 1 || k >= n
result = [];
return
end
reps = n^(k-1);
result = zeros(n^k, k);
cur_col = repmat(1:n, reps, 1);
result(:,1) = cur_col(:);
%// Base case: when k is 1, just return the
%// fully populated matrix 'result'
if k == 1
return
end
%// Recursively generate a matrix that will
%// be used to populate columns 2:end
next = nchoosek_replacement(n, k-1);
%// Repeatedly use the matrix above to
%// populate the matrix 'result'
for i = 1:n
cur_range = (i-1)*reps+1:i*reps;
result(cur_range, 2:end) = next;
end
end
With this function defined, you can now generate all possible sequences. In this case there are exactly 1000 so they could simply be shuffled with randperm. A more general approach is to sample from them with randsample, which would also allow for smaller matrices if desired:
max_value = 10;
row_size = 3;
num_rows = 1000;
possible = nchoosek_replacement(max_value, row_size);
indices = randsample(size(possible, 1), num_rows);
data = possible(indices, :);

Push Values Onto a Vector in a Control Loop

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

expand matrix in matlab?

I would like to expand matrix row by row under a conditional statement without initializing the matrix. In C++, simply I use std::vector and push_back method without initializing the size of the vector in C++. However, I want to do same scenario in Matlab. This is my pseudo code
for i = 1:lengt(data)
if ( condition )
K = [data(1) data(2) i]
end
K
Let us assume some working code to resemble your pseudo-code.
%// Original code
for i = 1:10
if rand(1)>0.5
data1 = rand(2,1)
K = [data1(1) data1(2) i]
end
end
Changes for "pushing data without initialization/pre-allocation":
To save data at each iteration we keeping on "stacking" data along a chosen dimension. This could be thought of as pushing data. For a 2D case, use either a "row vector push" or a "column vector push". For this case we are assuming a former case.
We don't index into K using the original iterator, but use a custom one,
that only increments when the condition is satisfied.
The code below must make it clear.
%// Modified code
count = 1; %// Custom iterator; initialize it for the iteration when condition would be satisfied for the first time
for i = 1:10
if rand(1)>0.5
data1 = rand(2,1)
K(count,:) = [data1(1) data1(2) i] %// Row indexing to save data at each iteration
count = count +1; %// We need to manually increment our custom iterator
end
end
If we assume from the above that data is an Nx2 matrix, and that you only want to save the rows that satisfy some condition, then you almost have the correct code to update your K matrix without having to initialize it to some size:
K = []; % initialize to an empty matrix
for i=1:size(data,1) % iterate over the rows of data
if (condition)
% condition is satisfied so update K
K = [K ; data(i,:) i];
end
end
K % contains all rows of data and the row number (i) that satisfied condition
Note that to get all elements from a row, we use the colon to say get all column elements from row i.

How can I shift array element using a for loop in Matlab?

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)]