Sort MATLAB Cell Array Across multiple columns - arrays

I have data that is of the following form:
'of' 45001 23366 21859591 52876216 0 45001
'on' 40649 23226 17940625 44201973 0 40649
'my' 37976 18338 11277975 47042676 0 37976
'me' 28707 18134 6546887 36222235 0 28707
I am wondering how in MATLAB I go about sorting say column 2 from largest to smallest but keep all the other rows associated with the one that's being sorted - this is stored in a cell array also.
Any help would be appreciated.

Although you're dealing with a cell array, the answer actually ends up being the same as that listed for numeric arrays in the closely-related questions I linked to in my above comment: simply use the function SORTROWS. Here's how you can sort the rows of your cell array according to the values in the second column (in descending order):
sortedCellArray = sortrows(cellArray,-2);
NOTE: It should be noted that the documentation for SORTROWS doesn't appear to explicitly say that the function will work with cell array inputs, but it does have an example showing that it works for them just like it does for any other array.

Related

array based sumif in excel by formula

So I m trying to find some alternative to sumifs in excel where each condition needs to be checked in a 2D range instead of a 1D range.
For example, in the below table I want the sum of values in column V for rows where A12 ("IJ") is present in range A2:C8 (P), B12 ("NM") is present in the range D2:F8 (S) and C12 ("XX") is present in range G2:I8 (A)
I am trying to find a solution involving an array-based formula (without VBA).
Like for example in the below-given formulas,
SUMPRODUCT((B2:B8'=A12)*J2:J8) will give an array-based calculation as follows
SUMPRODUCT({TRUE;FALSE;TRUE;FALSE;FALSE;TRUE;FALSE}*{22;79;45;67;43;72;52})
= SUMPRODUCT({22;0;45;0;0;72;0})
=139
It is easy when there is only one condition needs to be checked but like sumifs, I intend to check multiple conditions, but as soon as I add other conditions, the array becomes multidimensional and gives the wrong answer.
Example:
SUMPRODUCT((A2:C8=A12)*(D2:F8=B12)*J2:J8) breaks down to
=SUMPRODUCT(
{FALSE,TRUE,FALSE;FALSE,FALSE,FALSE;FALSE,TRUE,FALSE;FALSE,FALSE,FALSE;FALSE,FALSE,FALSE;FALSE,TRUE,FALSE;FALSE,FALSE,FALSE}*
{TRUE,FALSE,FALSE;FALSE,FALSE,FALSE;TRUE,FALSE,FALSE;FALSE,FALSE,FALSE;FALSE,FALSE,FALSE;TRUE,FALSE,FALSE;FALSE,FALSE,FALSE}
*J2:J8)
in the background what is happening is (example for 3rd row)
SUMPRODUCT( ({FALSE, TRUE ,FALSE} * {TRUE,FALSE,FALSE}) * 45 )
= SUMPRODUCT({FALSE,FALSE,FALSE} *45 )
=0
SUMPRODUCT(({FALSE,TRUE ,FALSE} + {TRUE,FALSE,FALSE}) * 45 )
= SUMPRODUCT({TRUE,TRUE,FALSE} *45 )
= 90
#expected answer =45
Can someone help me understand where I am going wrong or what I am missing?
If there is any other way then suggestions are always welcome.
Please note this is a dummy data actual data is very big for each header (P,S,A) there are values in 10 columns respectively and the number of rows is also very large.
Try this...
=SUMPRODUCT( ((A2:A8=A12)+(B2:B8=A12)+(C2:C8=A12)) * ((D2:D8=B12)+(E2:E8=B12)+(F2:F8=B12)) * ((G2:G8=C12)+(H2:H8=C12)+(I2:I8=C12)) * J2:J8 )
For SUMPRODUCT to work, the shape of the Boolean array needs to match the shape of the array you wish to conditionally sum.
J2:J8 is seven rows tall by one column wide.
The above formula creates an array of 1s and 0s from your three criteria ranges and shapes it into seven rows tall by one column wide.
At that point, SUMPRODUCT can do it's normal thing because the criteria array matches the dimension of the sum array J2:J8.

Mapping a 2D array into 1D array with variable column width

I know mapping 2D array into 1D array has been asked many times, but I did not find a solution that would fit a where the column count varies.
So I want get a 1-dimensional index from this 2-dimensional array
Col> _0____1____2__
Row 0 |_0__|_1__|_2__|
V 1 |_3__|_4__|
2 |_5__|_6__|_7__|
3 |_8__|_9__|
4 |_10_|_11_|_12_|
5 |_13_|_14_|
The normal formula index = row * columns + column does not work, since after the 2nd row the index is out of place.
What is the correct formula here?
EDIT:
The specific issue is that I have a list of items in with the layout like in the grid, but a one dimensional array for the data. So while looping through the elements in the UI, I need to get the correct data, but can only get the row and column for that element. I need to find a way to turn a row/column value into an index for the data-array
Bad picture trying to explain it
A truly optimal answer (or even a provably correct one) will depend on the language you are using and how it lays out memory for such arrays.
However, taking your question simply at face value, you have to know what the actual length of each row is in order to calculate a 1D index.
So either the row length follows some pattern that can be inferred from the data, or you have (or can write) a rlen = rowLength( 2dTable, RowNumber) function.
Then, depending on how big the tables are and how fast you need to run, you can calculate a 1D index from the 2d table by adding all the previous row lengths until the current row length is less than the 2d column index.
or build a 1d table of the row lengths (or commulative rowlengths) so you can scan it and so only call your rowlength function for each row only once.
With a better description of your problem, you might get a better answer...
For your example which alternates between 3 and 2 columns you can construct a formula:
index = (row / 2) * (3 + 2) + (row % 2 ? 3 : 0) + column
(C-like syntax, assuming integer division)
In general though, the one and only way to implement what you're doing here, jagged arrays, is to make an array of arrays, a.k.a. an Iliffe vector. That means, use the row number as index into an array of pointers which point to the individual row arrays containing the actual data.
You can have an additional 1D array having the length of the columns say "length". Then your formula is index=sum {length(i)}+column. i runs from 0 to row.

MATLAB: use strcmp(s1,s2) for variable length vector with strings

I have a query which I am trying to solve
I know that one can use strcmp(s1,s2) to compare two different strings to see whether they are the same. It gives 1 if that is the case.
However, how would one tackle this problem if you have a variable length array full of strings and you want to the whether all strings in the array are the same.
For example: ['NACA64A010' 'NACA64A010' 'NACA64A010' 'NACA64A010'] we can see that all the strings are the same in this array. However, how would one go about with using strcmp(s1,s2).
Thanks guys!
If you want all pairwise comparisons between strings: call ndgrid to generate indices of all combinations, and then index into your cell array of strings and call strcmp:
x = {'NACA64A010' 'NACA64A010' 'NACA64A010' 'NACA64A010'};
[ii, jj] = ndgrid(1:numel(x));
result = strcmp(x(ii), x(jj));
In this case
result =
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
because all strings are the same.
You probably had a pairwise comparison using strcmp in mind, but you can use it directly on cell arrays:
x={'NACA64A010' 'NACA64A010' 'NACA64A010' 'NACA64A010'}
result=all(strcmpi(x{1},x(2:end)))
Compare the first element to the remaining elements. It returns true only if all elements are equal. For a pairwise comparison you could us:
[~,~,c]=unique(x);
result=bsxfun(#eq,c,c.')
If you're solving the problem with a matrix (i.e. every row is a string) there are no particularly nice solutions in my opinion, but if your strings are contained into a cell array, things are getting easier and nicer.
So we start by creating such cell array:
myStrings={'NACA64A010' 'NACA64A010' 'NACA64A010' 'NACA64A010'};
where each cell contains a string. This will make your code more robust as well since every string can have a different length (this is not true if you concatenate all your strings in a matrix).
Then you specify which string you want to find inside such cell array:
stringThatMustBeTested='NACA64A010';
Now you can use cellfun(), which is a function that applies another function to every cell of a given cell array as follows:
results=cellfun(#(x) strcmp(x,stringThatMustBeTested),myStrings);
Such line simply means "apply strcmp() to every generic cell x inside myStrings and compare the cell with stringThatMustBeTested".
Variable results will be a logical output in which element j will be true if the j-th cell in your cell array is equal to the string you want to test. If results is entirely composed by 1s (which you can check as if sum(results)==length(results)), then all the strings are the same in myStrings (given that stringThatMustBeTested is the unique string in your cell array but anyways, this solution can be extended to a broader string search inside a cell).

Split array into smaller unequal-sized arrays dependend on array-column values

I'm quite new to MatLab and this problem really drives me insane:
I have a huge array of 2 column and about 31,000 rows. One of the two columns depicts a spatial coordinate on a grid the other one a dependent parameter. What I want to do is the following:
I. I need to split the array into smaller parts defined by the spatial column; let's say the spatial coordinate are ranging from 0 to 500 - I now want arrays that give me the two column values for spatial coordinate 0-10, then 10-20 and so on. This would result in 50 arrays of unequal size that cover a spatial range from 0 to 500.
II. Secondly, I would need to calculate the average values of the resulting columns of every single array so that I obtain per array one 2-dimensional point.
III. Thirdly, I could plot these points and I would be super happy.
Sadly, I'm super confused since I miserably fail at step I. - Maybe there is even an easier way than to split the giant array in so many small arrays - who knows..
I would be really really happy for any suggestion.
Thank you,
Arne
First of all, since you wish a data structure of array of different size you will need to place them in a cell array so you could try something like this:
res = arrayfun(#(x)arr(arr(:,1)==x,:), unique(arr(:,1)), 'UniformOutput', 0);
The previous code return a cell array with the array splitted according its first column with #(x)arr(arr(:,1)==x,:) you are doing a function on x and arrayfun(function, ..., 'UniformOutput', 0) applies function to each element in the following arguments (taken a single value of each argument to evaluate the function) but you must notice that arr must be numeric so if not you should map your values to numeric values or use another way to select this values.
In the same way you could do
uo = 'UniformOutput';
res = arrayfun(#(x){arr(arr(:,1)==x,:), mean(arr(arr(:,1)==x,2))), unique(arr(:,1)), uo, 0);
You will probably want to flat the returning value, check the function cat, you could do:
res = cat(1,res{:})
Plot your data depends on their format, so I can't help if i don't know how the data are, but you could try to plot inside a loop over your 'res' variable or something similar.
Step I indeed comes with some difficulties. Once these are solved, I guess steps II and III can easily be solved. Let me make some suggestions for step I:
You first define the maximum value (maxValue = 500;) and the step size (stepSize = 10;). Now it is possible to iterate through all steps and create your new vectors.
for k=1:maxValue/stepSize
...
end
As every resulting array will have different dimensions, I suggest you save the vectors in a cell array:
Y = cell(maxValue/stepSize,1);
Use the find function to find the rows of the entries for each matrix. At each step k, the range of values of interest will be (k-1)*stepSize to k*stepSize.
row = find( (k-1)*stepSize <= X(:,1) & X(:,1) < k*stepSize );
You can now create the matrix for a stepk by
Y{k,1} = X(row,:);
Putting everything together you should be able to create the cell array Y containing your matrices and continue with the other tasks. You could also save the average of each value range in a second column of the cell array Y:
Y{k,2} = mean( Y{k,1}(:,2) );
I hope this helps you with your task. Note that these are only suggestions and there may be different (maybe more appropriate) ways to handle this.

length in 2 dimension array

var example is a 2-dimension array. example.length will give values like 14.3
But how can I get an integer for the length of example in second dimension, like 3 in this case?
Thank you!
If the array is homogeneous (which is always the case when such an array is the result of a getValues() call in a spreadsheet range for example) you can simply write :
example[0].length
EDIT : a few comments to be more clear ...
The 2D array you get from example = range.getValues() is always an array of rows data.
The number of rows is represented by example.length and the inner array length (representing rows content) is always example[0].length, which is actually the number of columns

Resources