Multi-line fprintf() using one element from each array per line - matlab

I've hit some unexpected behaviour using the fprintf() function in MATLAB. I'm trying to print a multi-line file using the contents of a cell array and a numerical array. I know that I can use the fprintf() function as follows to print out the contents of a cell array:
myCellArray = {'one','two','three'};
fprintf('%s\n',myCellArray{:})
This results in the following output:
one
two
three
I can also print out a numerical array as follows:
myNumericalArray = [1,2,3];
fprintf('%i\n',myNumericalArray)
This results in:
1
2
3
However, the weird behaviour appears if I try to mix these, as follows:
fprintf('%s is %i\n',myCellArray{:},myNumericalArray)
This results in:
one is 116
wo is 116
hree is 1
I think this happens because MATLAB tries to print the next entry in myCellArray in the place of the %i, rather than using the first entry in myNumericalArray. This is evident if I type the following:
fprintf('%s %s\n',myCellArray{:},myCellArray{:})
Which results in:
one two
three one
two three
...Is there some way to ensure that only one element from each array is used per line?

I agree with your idea. So, I could only think of circumventing this by creating a combined cell array with alternating values from your two initial arrays, see the following code:
myCombinedArray = [myCellArray; mat2cell(myNumericalArray, 1, ones(1, numel(myNumericalArray)))];
fprintf('%s is %i\n', myCombinedArray{:})
Gives the (I assume) desired output:
one is 1
two is 2
three is 3

fprintf(formatSpec,A1,...,An) will print all the element of A1 in column order, then all the element of A2 in column order... and size(A1) is not necessarily equal to size(A2).
So in your case the easiest solution is IMO the for loop:
for ii = 1:length(myCellArray)
fprintf('%s is %d\n',myCellArray{ii},myNumericalArray(ii))
end
For the small explanation foo(cell{:}) is similar to the splat operator (python, ruby,...) so matlab will interpret this command as foo(cell{1},cell{2},...,cell{n}) and this is why your two arguments are not interpreted pair-wise.

This is similar to the loop solution, only more compact:
arrayfun(#(c,n) fprintf('%s is %i\n', c{1}, n), myCellArray, myNumericalArray)

Related

Matlab: Use Splitapply to write multiple files

I have grouped tables by a variable and I am trying to write multiple files based on the grouping variable. But it does not work.
I used findgroups and splitapply, but the splitapply is where I am having problems.
Here is one version of the commands I am using:
load patients;
G=findgroups(Gender);
func=#(x,y) csvwrite(x,y);
splitapply(func,Gender,Weight,G);
I am getting the following error message:
Error using splitapply (line 132)
Applying the function '#(x,y)csvwrite(x,y)' to the 1st group of data generated the following error:
FILENAME must be a character vector or string scalar.
When I figure out how to use this, I will be using it on large datastore tall arrays. Please help !
The problem is that the first parameter of csvwrite must be a file name.
In your code sample, the first parameter to csvwrite is a cell array, and not a string.
You can see it by using the following trick:
func=#(x,y) display(x);
The output of splitapply(func,Gender,Weight,G) is:
x =
53×1 cell array
{'Female'}
{'Female'}
{'Female'}
...
x =
47×1 cell array
{'Male'}
{'Male'}
{'Male'}
Solution:
Use x{1} instead of x:
func=#(x,y) csvwrite(x{1}, y);
It's recommended to add file extension like .txt to file name:
func=#(x,y) csvwrite([x{1}, '.txt'], y);
Remark:
It's possible that the combination of splitapply with csvwrite misses the original intent of splitapply function.
According to documentation it looks like splitapply is better fitted for statistical calculations (and not intended to be used for I/O operations [writing files]).
I am not sure whether the above code pattern is the right way for "using it on large datastore tall arrays".
Complete code sample:
load patients;
G=findgroups(Gender);
%The first parameter of csvwrite must be a file name.
%x{1} = 'Male' for all the Male group, and 'Female' for all the Female group.
%[x{1}, '.txt'] adds a '.txt' extension to the file name.
%
%y will be array of Weight like
%[71
% 69
% 68]
func=#(x,y) csvwrite([x{1}, '.txt'], y);
splitapply(func,Gender,Weight,G)

What is the meaning of this command

capi = cell2mat(arrayfun(#(b) sum(resulti == b,1),nonzeros(unique(resulti)), 'UniformOutput', false))
why when I used that code, my code cannot run and there was command like the following command?
??? Array dimensions must match for binary array op.
All this can be found via Matlab's documentation, which should always be your first step!
Having said that, here's a breakdown of your command:
cell2mat: convert a cell array to a matrix according to some format you define
arrayfun: evaluate some function for all elements in an array. The function may be an anonymous function (e.g., #(b) sum(resulti == b,1))
sum: sum all the elements of a matrix in a particular direction. Direction 1: down the rows, direction 2: along the columns, etc.
nonzeros: form new array by removing all zeros from the input array. This will output a column vector, irrespective of the input's shape.
unique: return the input array with all duplicates of all values removed. The output will also be sorted.
Type help [command] or doc [command] for more information on all these commands (which I recommend you do!)
Now, combining these into your command:
A = nonzeros(unique(resulti))
will return all unique entries in a column vector, with any zero removed.
B = arrayfun(#(b)sum(resulti==b), A, 'UniformOutput', false)
will run the function #(b) sum(resulti == b,1) on all entries of the newly created column vector A, and collect them in a cell-array B (cell, because 'UniformOutput' is set to false). This function will simply compare each element of resulti against the running index b, and find the total count along the rows. Then, finally,
capi = cell2mat(B)
will convert the cell-array B back to a normal Matlab array.
The objective of this command seems to be to count the number of non-unique occurrences on each of the colums of resulti. As hinted at by #GuntherStruyf, this whole command seems a hacked-together, forced one-liner, rather than well-manageable, readable code. I would personally opt to break it over several lines, avoid arrayfun (slow) and instead use bsxfun or a for-loop (faster (yes, also the for-loop), better readable).
But that's a matter of opinion (which goes against popular opinion :)

foreach loop with strings in Matlab

I want to create a loop that will iterate over several strings, but unable to do so in Matlab.
What works is:
for i=1:3
if (i==1)
b='cow';
elseif (i==2)
b='dog';
else
b='cat';
end
disp(b);
end
and the result is:
cow
dog
cat
But what I want is something more elegant that will look like:
for i=['cow','dog','cat']
disp (i);
end
and give the same result.
Is there an option in Matlab to do this?
ADDITION:
I need the words as strings later on to use and not just to display (the disp was just as an example). I've tried to use cell arrays in my real program:
clear all;
close all;
clc;
global fp_a
global TEST_TYPE
global SHADE_METHODE
for fp_a=11:24
for shade={'full','fast'}
SHADE_METHODE=shade(1);
for test={'bunny','city'}
TEST_MODE=test(1);
fprintf ('fp_a:%d | test: %s | shade: %s',fp_a,TEST_TYPE,SHADE_METHODE);
ray_tracing;
end
end
end
It doesn't work as the values stay as cells and not strings I get the error message:
??? Error using ==> fprintf Function is not defined for 'cell' inputs.
*-I don't really need the fprintf I just use it to check that the values are correct.
**-ray_tracing is my code that uses the values of the strings
Or you can do:
for i={'cow','dog','cat'}
disp(i{1})
end
Result:
cow
dog
cat
Your problems are probably caused by the way MATLAB handles strings. MATLAB strings are just arrays of characters. When you call ['cow','dog','cat'], you are forming 'cowdogcat' because [] concatenates arrays without any nesting. If you want nesting behaviour you can use cell arrays which are built using {}. for iterates over the columns of its right hand side. This means you can use the idiom you mentioned above; Oli provided a solution already. This idiom is also a good way to showcase the difference between normal and cell arrays.
%Cell array providing the correct solution
for word = {'cow','dog','cat'}
disp(word{1}) %word is bound to a 1x1 cell array. This extracts its contents.
end
cow
dog
cat
%Normal array providing weirdness
for word = ['cow','dog','cat'] %Same as word = 'cowdogcat'
disp(word) %No need to extract content
end
c
o
w
d
o
g
c
a
t
Sure! Use cell arrays for keeping strings (in normal arrays, strings are considered by character, which could work if all strings have the same length, but will bork otherwise).
opts={'cow','dog','cat'}
for i=1:length(opts)
disp(opts{i})
end
Use string arrays which where introduced in R2017a I believe. Note the double-quotes:
for i = ["cow", "dog", "cat"]
disp(i);
end

Concatenate equivalent in MATLAB for a single value

I am trying to use MATLAB in order to generate a variable whose elements are either 0 or 1. I want to define this variable using some kind of concatenation (equivalent of Java string append) so that I can add as many 0's and 1's according to some upper limit.
I can only think of using a for loop to append values to an existing variable. Something like
variable=1;
for i=1:N
if ( i%2==0)
variable = variable.append('0')
else
variable = variable.append('1')
i=i+1;
end
Is there a better way to do this?
In MATLAB, you can almost always avoid a loop by treating arrays in a vectorized way.
The result of pseudo-code you provided can be obtained in a single line as:
variable = mod((1:N),2);
The above line generates a row vector [1,2,...,N] (with the code (1:N), use (1:N)' if you need a column vector) and the mod function (as most MATLAB functions) is applied to each element when it receives an array.
That's not valid Matlab code:
The % indicates the start of a comment, hence introducing a syntax error.
There is no append method (at least not for arrays).
Theres no need to increment the index in a for loop.
Aside of that it's a bad idea to have Matlab "grow" variables, as memory needs to be reallocated at each time, slowing it down considerably. The correct approach is:
variable=zeros(N,1);
for i=1:N
variable(i)=mod(i,2);
end
If you really do want to grow variables (some times it is inevitable) you can use this:
variable=[variable;1];
Use ; for appending rows, use , for appending columns (does the same as vertcat and horzcat). Use cat if you have more than 2 dimensions in your array.

matlab - print subarray of two dimensional array

hi let's assume i have the following in matlab
h = [0,0,0,1;
1,1,1,1];
now how can i print all the values of the first subarray, i.e. 0,0,0,1
or for example the second subarray 1,1,1,1. thanks !
You can access just the first row of your matrix by doing
firstRow = h(1,:)
Similarly, you could access just the third column by
thirdColumn = h(:,3)
I suggest you look into the MATLAB help under "Matrix Indexing" as this is really basic stuff (and there's a lot of other nifty things you can do to access a subset of a matrix)
For printing, you can omit the final ;, or look into functions display and fprintf.