Loading arrays of different sizes into a single array - arrays

I have 100 arrays with the dimension of nx1. n varies from one array to the next (e.g, n1 = 50, n2 = 52, n3 = 48 etc.). I would like to combine all these arrays into a single one with the dimension of 100 x m with m being the max of n's.
The issue I am running into is that as n varies, Matlab will throw out an error says that the dimensions mismatch. Is there a way to get around this so I can pad "missing" cell with N/A? For instance, if the first array contains 50 elements (i.e., n1 = 50) like this:
23
31
6
...
22
the second array contains 52 elements (i.e., n2 = 52) like this:
25
85
41
...
8
12
66
The result should be:
23 25
31 85
6 41
... ...
22 8
N/A 12
N/A 66
Thanks to the community in advance!

Here is another approach without eval.
array_lengths = cellfun(#numel, arrays);
max_length = max(array_lengths);
result = nan(max_rows, num_arrays);
for r=1:num_arrays
result(1:array_lengths(r),r) = arrays{r}(1:array_lengths(r));
end
Some explanation: I'm assuming your arrays are stored in a cell to begin with. Here is some code to generate fictitious data with the dimensions you gave:
% some dummy data for your arrays.
num_arrays = 100;
primerArrayCell = num2cell(ones(1,num_arrays)); % , 1, ones(1, num_arrays));
arrays = cellfun(#(c) rand(randi(50, 1),1), primerArrayCell, 'uniformoutput',false);
You can use cellfun with an anonymous function to get the lengths of each individual array:
% Assume your arrays are in a cell of arrays with the variable name arrays
array_lengths = cellfun(#numel, arrays);
max_length = max(array_lengths);
Allocate an array of nan values to store your result
% initialize your data to nan's.
result = nan(max_rows, num_arrays);
Then fill in the non-nan values based on the length of the arrays calculated previously.
for r=1:num_arrays
result(1:array_lengths(r),r) = arrays{r}(1:array_lengths(r));
end

You may want to consider using structure arrays for storing such datasets as it makes everything easier when merging them into a single array.
But to answer your question, if you have arrays like this:
a1 = 1:20; % array of size 1 x 20
n1 = numel(a1); % 20
a2 = 50:60; % array of size 1 x 11
n2 = numel(a2); % 11
... say you have nArrs arrays
Given nArrs arrays for example, you can create the desired matrix res like this:
m = max([n1, n2, .... ]);
res = ones(m,nArrs) * nan; % initialize the result matrix w/ nan
% Manually
res(1:n1,1) = a1.';
res(1:n2,2) = a2.';
% ... so on
% Or use eval instead like this
for i = 1:nArrs
eval(['res(1:n' int2str(i) ', i) = a' int2str(i) '.'';'])
end
Now bear in mind that using eval is NOT recommended but hopefully that just gives you an idea as to what to do. If you did use structures, you can replace eval with something more efficient and robust like arrayfun for instance.

Related

Matlab make new array of values without a loop

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, []);

reversing shuffling of array by indexing

I have a matrix whose columns which was shuffled according to some index. I know want to find the index that 'unshuffles' the array back into its original state.
For example:
myArray = [10 20 30 40 50 60]';
myShuffledArray = nan(6,3)
myShufflingIndex = nan(6,3)
for x = 1:3
myShufflingIndex(:,x) = randperm(length(myArray))';
myShuffledArray(:,x) = myArray(myShufflingIndex(:,x));
end
Now I want to find a matrix myUnshufflingIndex, which reverses the shuffling to get an array myUnshuffledArray = [10 20 30 40 50 60; 10 20 30 40 50 60; 10 20 30 40 50 60]'
I expect to use myUnshufflingIndex in the following way:
for x = 1:3
myUnShuffledArray(:,x) = myShuffledArray(myUnshufflingIndex(:,x), x);
end
For example, if one column in myShufflingIndex = [2 4 6 3 5 1]', then the corresponding column in myUnshufflingIndex is [6 1 4 2 5 3]'
Any ideas on how to get myUnshufflingIndex in a neat vectorised way? Also, is there a better way to unshuffle the array columnwise than in a loop?
You can get myUnshufflingIndex with a single call to sort:
[~, myUnshufflingIndex] = sort(myShufflingIndex, 1);
Alternatively, you don't even need to compute myUnshufflingIndex, since you can just use myShufflingIndex on the left hand side of the assignment to unshuffle the data:
for x = 1:3
myUnShuffledArray(myShufflingIndex(:, x), x) = myShuffledArray(:, x);
end
And if you'd like to avoid a for loop while unshuffling, you can vectorize it by adding an offset to each column of your index, turning it into a matrix of linear indices instead of just row indices:
[nRows, nCols] = size(myShufflingIndex);
myUnshufflingIndex = myShufflingIndex+repmat(0:nRows:(nRows*(nCols-1)), nRows, 1);
myUnShuffledArray = nan(nRows, nCols); % Preallocate
myUnShuffledArray(myUnshufflingIndex) = myShuffledArray;

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 function to replace randi to generate a matrix

I have a matlab problem to solve. In have two vectores that limit my space, x_low and x_high. The matrix pos needs to have values within this spaces and each column of the matrix has different bounds given by the two vectores. Now my problem is that randi gives valus between two integers but i need to change the bounds for each columns. There is another way to use randi or a different matlab function to do this?
I know there are better codes to do this but i'm starting to use matlab and i know to do it this way, any aid is welcome
x_low = [Io_low, Iirr_low, Rp_low, Rs_low, n_low]; % vector of constant values
x_high = [Io_high, Iirr_high, Rp_high, Rs_high, n_high]; % vector of constant values
pos = rand(particles, var);
var = length(x_high);
for i = 1: particles % rows
for k = 1: var %columns
if pos(i, k) < x_low(k) || pos(i, k) > x_high(k) % if the position is out of bounder
pos(i, k) = randi(x_low(k), x_high(k), 1); % fill it with a particle whithin the bounderies
end
end
end
If I understand correctly, you need to generate a matrix with integer values such that each column has different lower and upper limits; and those lower and upper limits are inclusive.
This can be done very simply with
rand (to generate random numbers between 0 and 1 ),
bsxfun (to take care of the lower and upper limits on a column basis), and
round (so that the results are integer values).
Let the input data be defined as
x_low = [1 6 11]; %// lower limits
x_high = [3 10 100]; %// upper limits
n_rows = 7; %// number of columns
Then:
r = rand(n_rows, numel(x_low)); %// random numbers between 0 and 1
r = floor(bsxfun(#times, r, x_high-x_low+1)); %// adjust span and round to integers
r = bsxfun(#plus, r, x_low); %// adjust lower limit
gives something like
r =
2 7 83
3 6 93
2 6 22
3 10 85
3 7 96
1 10 90
2 8 57
If you need to fill in values only at specific entries of matrix pos, you can use something like
ind = bsxfun(#lt, pos, x_low) | bsxfun(#gt, pos, x_high); %// index of values to replace
pos(ind) = r(ind);
This a little overkill, because the whole matrixd r is generated only to use some of its entries. To generate only the needed values the best way is probably to use loops.
You can use cellfun for this. Something like:
x_low = [Io_low, Iirr_low, Rp_low, Rs_low, n_low];
x_high = [Io_high, Iirr_high, Rp_high, Rs_high, n_high];
pos = cell2mat(cellfun(#randi, mat2cell([x_low' x_high'], ones(numel(x_low),1), 1), repmat({[particles 1]}, [numel(x_low) 1)])))';
Best,

Select range based on contents of an array

I have two arrays. I'd like to copy ranges of data from one of them, based on a list of array locations stored in the other. For example, if the first array were comprised of 100 rows and 2 columns, I might like to copy rows 10-20, rows 60-70 and rows 75-79. If that were the case, then the contents of the second array would be as follows:
b =
10 20
60 70
75 79
In order to select the appropriate rows of the first array based on the second (let's call it 'a'), I would do the following:
b = [a(1,1):a(1,2) a(2,1):a(2,2) a(3,1):a(3,2)]
This works, and returns array 'b' which is basically array 'a' with the correct contents extracted.
The problem is, array 'b' actually contains between 50 and 60 rows (i.e ranges to be included).
How do I make the above code more efficient, such that it works for any number of rows in 'b'?
Example:
a = rand(100,1);
ranges = [
10 20
60 70
75 79
];
idx = arrayfun(#colon, ranges(:,1), ranges(:,2), 'Uniform',false);
idx = [idx{:}];
b = a(idx)
You could use a for, assuming ranges of values to be extracted from a are in b, and should go to c:
% input
a = rand(100,2);
b = [10 20; 60 70; 75 79];
% output
c = zeros(1,2);
for i = 1:size(b,1)
c = vertcat(c a(b(i,1):b(i,2), :));
end
c = c(2:size(c,1), :);
A solution using cellfun and cell arrays:
% Some example data:
a = reshape(1:100, 10, 10);
b = [ 2 3; 5 8; 10 10 ];
Here's the code:
bCell = mat2cell(b, 3, [ 1 1 ]);
aRows = cell2mat(arrayfun(#(x,y) a(x:y, :), bCell{1}, bCell{2}, 'UniformOutput', false));

Resources