0
votes

A few days ago I posted this question and got the following splendid solution:

fid = fopen('C:\Testes_veloc\test.txt', 'Wt');
fmt = sprintf('%s;%d;%%d;%d;%d;%%d;%%d;%%d;%%.4f \\n',str1,num1,0,2)
[a,b,c,d] = ndgrid(vect2,vect1,day,1:15);
out = sprintf(fmt, [d(:), c(:), b(:), a(:), reshape(permute(MD,[2,1,3,4]),[],1)]'); 
fprintf(fid, '%s', out);

The variables str1, num1, day, vect1, vect2 and MD are inputs of this function:

  • str1 is a string 1x1
  • num1 is an integer 1x1
  • day is a vector 10x1
  • vect1 is a vector 7x1
  • vect2 is a vector 180x1
  • MD is a 4D matrix (7x180x10x15)

The objective was to have a text file as follows:

result.txt:
RED;12;7;0;2;1;4;7;0.0140
RED;12;7;0;2;2;9;7;0.1484
RED;12;7;0;2;3;7;4;0.1787
RED;12;7;0;2;4;2;6;0.7891
RED;12;7;0;2;5;9;6;0.1160
RED;12;7;0;2;6;9;1;0.9893

However, str1 is not a 1x1 string; it's a vector of names (189000x1), that has the length of the text that I desire. In other words, instead of only 'RED', I have many different others strings. Is it possible to adjust this vectorized loop to this situation?

I tried this (add the str1(:) to the concatenation part), but unsuccessfully:

fmt = sprintf('%%s;%s;%d;%%d;%d;%d;%%d;%%d;%%d;%%.4f \\n',str1,num1,0,2)
out = sprintf(fmt, [str1 (:), d(:), c(:), b(:), a(:), reshape(permute(MD,[2,1,3,4]),[],1)]'); 

For example, str(1,:) = 'RED'; str(2,:) = 'FHAW'; str(3,:) = 'KI81'; a cell like this. It fails to concatenate the string to the numbers. Does anyone have solution?

Thanks in advance.

1
Please provide a short example of names. The solution might not be faster than a loop. - Oleg
No reason to be sorry, I just think that you might have the code snippets already, it would be more meaningful if you did the comparison directly as opposed to some generic counterexample that I might provide. Also, in the previous question Floris provided a timed solution. You could adapt that to your timing purposes. - Oleg

1 Answers

1
votes

sprintf (like fprintf) fills format fields using the arguments in the order they are provided. If you provide more arguments than the format calls for, these functions repeat the format with the additional functions:

sprintf('%s %i\n', 'a', 1, 'b', 2, 'c', 3)

% returns

ans =

a 1
b 2
c 3

Using Matlab's cell unravelling technique, you can prepare your arguments first, then pass them to the sprintf:

tmp = {'a', 1, 'b', 2, 'c', 3};
sprintf('%s %i\n', tmp{:})

You can get fancier by concatenating cell arrays:

tmp1 = {'a','b','c'};
tmp2 = [1 2 3];
tmp = [tmp1' num2cell(tmp2')]'
sprintf('%s %i\n', tmp{:})

% Returns

tmp = 

    'a'    'b'    'c'
    [1]    [2]    [3]


ans =

a 1
b 2
c 3

Note that the layout of tmp is transposed of the layout in the format. This is because Matlab reads the data in row-major order, so it will march down rows, then columns, to get the arguments for sprintf.

So, in your scenario, you need to create a large cell array with your arguments, then pass that to sprintf.

fid = fopen('C:\Testes_veloc\test.txt', 'Wt');
fmt = sprintf('%%s;%d;%%d;%d;%d;%%d;%%d;%%d;%%.4f \\n',num1,0,2)
[a,b,c,d] = ndgrid(vect2,vect1,day,1:15);
tmp = [str(:) num2cell([d(:) c(:) b(:) a(:) reshape(permute(MD,[2,1,3,4]),[],1)]'])]';
fprintf(fid, fmt, tmp{:});
fclose(fid);