Apply a string value to several positions of a cell array - arrays

I am trying to create a string array which will be fed with string values read from a text file this way:
labels = textread(file_name, '%s');
Basically, for each string in each line of the text file file_name I want to put this string in 10 positions of a final string array, which will be later saved in another text file.
What I do in my code is, for each string in file_name I put this string in 10 positions of a temporary cell array and then concatenate this array with a final array this way:
final_vector='';
for i=1:size(labels)
temp_vector=cell(1,10);
temp_vector{1:10}=labels{i};
final_vector=horzcat(final_vector,temp_vector);
end
But when I run the code the following error appears:
The right hand side of this assignment has too few values to satisfy the left hand side.
Error in my_example_code (line 16)
temp_vector{1:10}=labels{i};
I am too rookie in cell strings in matlab and I don't really know what is happening. Do you know what is happening or even have a better solution to my problem?

Use deal and put the left hand side in square brackets:
labels{1} = 'Hello World!'
temp_vector = cell(10,1)
[temp_vector{1:10}] = deal(labels{1});
This works because deal can distribute one value to multiple outputs [a,b,c,...]. temp_vector{1:10} alone creates a comma-separated list and putting them into [] creates the output array [temp_vector{1}, temp_vector{2}, ...] which can then be populated by deal.
It is happening because you want to distribute one value to 10 cells - but Matlab is expecting that you like to assign 10 values to 10 cells. So an alternative approach, maybe more logic, but slower, would be:
n = 10;
temp_vector(1:n) = repmat(labels(1),n,1);

I also found another solution
final_vector='';
for i=1:size(labels)
temp_vector=cell(1,10);
temp_vector(:,1:10)=cellstr(labels{i});
final_vector=horzcat(final_vector,temp_vector);
end

Related

Matlab: Export concatenation of cell arrays into a txt file

I have two different sets of arrays within an array, which I called:
y={...}; % cell array of 1x1, with a 26x1 cell array within it.
Only_Data={...} %cell array of 525x1, with 525 different 1x12 cell arrays
The data that's within the arrays is string. I want to concatenate these two arrays into one and print that final result into a .txt file. But I'm having problems doing the last part.
This is what I've done for that purpuse:
new_subject3=[y; Only_Data];
new_subject3;
outfile='mynewfile';
filename=[outfile,'.txt'];
fid=fopen(filename,'w');
[nrows,ncols] = size(new_subject3);
for row = 1:nrows
fprintf(fid ,'%s\n', new_subject3{row}{1:end});
end
fclose(fid);
For some reason I'm not aware of, it only prints the 'y' array, but doesn't print anything from the 'Only_Data' array. Why would that be? I'm clueless. I'm sure it's not about the type of data, but further than that I don't know.
I'll be glad to learn how to do this, thanks in advance.

Keeping values of cell arrays when exporting to Excel

I have a cell array. Some of the elements in this cell array contains zeros as the first character and the whole element is only numbers (double) as well. When exporting these to Excel (which I prefer), the zeros are deleted and converting it to a number.
Let's take an example to illustrate my problem. I have a cell array with 10 elements:
NodeID = {'0000006';
'0000011';
'000011R';
'000016R';
'000021R';
'B276_2';
'EB 7.55';
'EB2521';
'EllebaekOPlB1';
'EllebaekOplB10'};
The first two elements contains zeros until the number 6 and 11, respectively. Unlike the third element and so forth, where letters are involved. So when exporting NodeID to Excel, it returns this in a column (I use writetable command by the way):
6
11
000011R
000016R
000021R
B276_2
EB 7.55'
EB2521
EllebaekOPlB1
EllebaekOplB10
Notice the removal of zeros for the first two elements. Now I know that in Excel, it will keep all the content with the addition of a quote symbol ' in front of the cell, eg. '0000006 for the first element.
I have searched in many places to find a solution to this. But is there a good way to avoid this from happening? Either by somehow adding an extra ยด or some other magical trick which I have not seen?
Thank you in advance!
One alternative (if your values are in a cell, as you say they are):
filename = 'NodeID.xlsx';
NodeID2 = cellfun(#(C) ['''',C], NodeID,'UniformOutput', false)
xlswrite(filename, NodeID2)
This gives you:
NodeID2 =
''0000006'
''0000011'
''000011R'
''000016R'
''000021R'
''B276_2'
''EB 7.55'
''EB2521'
''EllebaekOPlB1'
''EllebaekOplB10'
And an Excel file looking like this:
The cellfun line is equivalent to:
for ii = 1:numel(NodeID)
NodeID2{ii,1} = ['''', NodeID{ii}];
end
The part ['''', NodeID{ii}] inserts a single quotation mark in front for the string. Relevant answer.

Efficient allocation of cell array in matlab

I have some which converts a cell array of strings into a cell array of characters.
Note. For a number of reasons, both the input (C) and the output (C_itemised) must be cell arrays.
The cell array of strings (C) is as follows:
>> C(1:10)
ans =
't1416933446'
''
't1416933446'
''
't1416933446'
''
't1416933446'
''
't1416933446'
''
I have only shown a portion of the array here. In reality it is ~28,000 rows in length.
I have some code which does this, although it is very inefficient. The cellstr function takes up 72% of the code's time, as it is currently called thousands of times. The code is as follows:
C_itemised=cell(length(C),500);
for i=3:length(C)
temp=char(C{i});
for j=1:length(temp)
C(i-2,j)=cellstr(temp(j));
end
end
I have a feeling that some minor modifications could take out the inner loop, thus cutting down the overall running time substantially. I have tried a number of ways to do this, but I think I keep getting confused about whether to use {} or (), and haven't been able to find anything online that can help me. Can anyone see a way to make the code more efficient?
Please also note that this function is used in conjunction with other functions, and does work, although it is running slower than would be ideal. Therefore, I do not wish to change the format of C_itemised.
EDIT:
(A sample of) the output of my current function is:
C_itemised(1,1:12)
ans =
Columns 1 through 12
't' '1' '4' '1' '6' '9' '3' '3' '4' '4' '6' []
One thing I can suggest is to use the undocumented function sprintfc. This function is hidden from normal use in MATLAB, but it is used internally with a variety of other functions. Mainly, if you tried doing help sprintfc, it'll say that there's no function found! It's cool to sniff around the source sometimes!
How sprintfc works is that you provide it a formatting string, much like printf, and the data you want printed. It will take each individual element in the data and place them into individual cell arrays. As an example, supposing I had a string D = 'abcdefg';, if we did:
out = sprintfc('%c', D);
We get:
>> celldisp(out)
out{1} =
a
out{2} =
b
out{3} =
c
out{4} =
d
out{5} =
e
out{6} =
f
out{7} =
g
As such, it takes each element in your string and places them as individual characters serving as individual elements in a new cell array. The %c formatting string means that we want to print a single character per element. Check out the link to Undocumented MATLAB that I posted above if you want to learn more!
Therefore, try simplifying your loop to this:
C_itemised=cell(length(C));
for i=1:length(C)
C_itemised{i} = sprintfc('%c', C{i});
end
C_itemised will be a cell array, where each element C_itemised{i} is another cell array, with each element in this cell array being a single character that is composed of the string C{i}.
Minor Note
You said you were confused about {} and () in MATLAB for cells. {} is used to access individual elements inside the cell. So doing C{1} for example will grab whatever is stored in the first element of the cell array. () is used to slice and index into the cells. For example, if you wanted to make another cell array that is a subset of the current one, you would do something like C(1:3). This will create a three element cell array which is composed of the first three cells in C.

append char array to cell array in matlab

I am a Matlab beginner, as will soon be very obvious. I am trying to assemble an cell array that has a single column of filenames.
I have multiple sessions. Each session should have 56 filenames (but some could be short or long, so I'd honestly prefer a solution that wouldn't break on encountering a short session). I need to loop over sessions and append the names in each subsequent session to my cell array, so that after two sessions the dimensions are 112, 1.
In other words, I'd like an array that went:
P =
/data/session1/dvol1.img
/data/session1/dvol2.img
...
/data/session1/dvol56.img
/data/session2/dvol1.img
/data/session2/dvol2.img
...
/data/session2/dvol56.img
and so on if there are more than two sessions.
The function I have that finds the filenames in the session is spm_select. It returns a char array of all the files in a directory that match a regular expression, in this case, 56 files for each session directory.
(I recognize my question is very similar to the question here: Using loops to get multiple values into a cell but I couldn't figure out an answer to my question since that person is only trying to append a single value at a time.)
I have tried a lot of things that haven't worked.
This:
data_path = '/foo/bar/';
subjects = {'test1'};
sessions = {'session1' 'session2' };
for i=1:numel(subjects)
clear P
P=cell(56*numel(sessions),1);
for j=1:numel(sessions)
P{(j-1)*56+1} = spm_select('FPList', fullfile(data_path,subjects{i}, sessions{j}), '^d.*\.img$');
end
end
generated a cell array that was 112x1, but had a first element that was 56x57 char array, that is, the filenames of all files in my first session directory, and none of them from the second.
I'm not sure how useful it would be to recapitulate every wrong-headed thing I've done, so I won't.
Thanks in advance for your help.
Editing to include sample output from spm_select by request:
>> output = spm_select('FPList', fullfile(data_path,subjects{i}, sessions{j}), '^d.*\.img$')
output =
/home/katie/Desktop/sample/test1/run_1L3/draghf000001.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000035.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000069.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000103.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000137.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000171.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000205.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000239.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000273.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000307.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000341.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000375.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000409.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000443.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000477.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000511.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000545.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000579.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000613.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000647.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000681.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000715.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000749.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000783.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000817.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000851.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000885.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000919.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000953.img
/home/katie/Desktop/sample/test1/run_1L3/draghf000987.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001021.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001055.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001089.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001123.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001157.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001191.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001225.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001259.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001293.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001327.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001361.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001395.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001429.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001463.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001497.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001531.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001565.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001599.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001633.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001667.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001701.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001735.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001769.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001803.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001837.img
/home/katie/Desktop/sample/test1/run_1L3/draghf001871.img
>> class(output)
ans =
char
>> size(output)
ans =
56 57
>>
Edit: Ok, problem solved. Here is the code I eventually used:
data_path = '/foo/bar';
subjects = {'test1'};
sessions = {'session1' 'session2' };
output={};
for i=1:numel(subjects)
for j=1:numel(sessions)
files=spm_select('FPList', fullfile(data_path,subjects{i},sessions{j}), '^d.*\.img$')
f_c=cellstr(files);
output=vertcat(output,f_c);
end
end
I think the answer to how "do you get a char array to append to a column cell array vertically" is convert it to a cell array and use vertcat.
You can try this code:
function output=file_list(path)
output={};
subjects=dir(path);
for a=3:length(subjects)
sessions=dir(fullfile(path,subjects(a).name));
for b=3:length(sessions)
files=dir(fullfile(path,subjects(a).name,'/',sessions(b).name,'/*.img'));
f_c=struct2cell(files);
f=f_c(1,:)';
output=vertcat(output,fullfile(path,subjects(a).name,'/',sessions(b).name,'/',f));
end
end
One drawback of this code is that the size of output grows inside the loop. Here is an example:
path='/home/naveen/Desktop/example/'; % path is the main directory in which the data of
% subjects is stored in sub directories.
output=file_list(path)
The output is:
output =
'/home/naveen/Desktop/example/subject_1/session_1/lipo2.png'
'/home/naveen/Desktop/example/subject_1/session_1/lipo_6.png'
'/home/naveen/Desktop/example/subject_1/session_1/lps_4.png'
'/home/naveen/Desktop/example/subject_1/session_2/ltx_2.png'
'/home/naveen/Desktop/example/subject_1/session_2/ltx_2_1.png'
'/home/naveen/Desktop/example/subject_1/session_2/ltx_2_3.png'
'/home/naveen/Desktop/example/subject_1/session_2/ltx_4.png'
'/home/naveen/Desktop/example/subject_1/session_2/ltx_6.png'
'/home/naveen/Desktop/example/subject_2/session_1/lipo2.png'
'/home/naveen/Desktop/example/subject_2/session_1/lipo_6.png'
'/home/naveen/Desktop/example/subject_2/session_1/lps_4.png'
'/home/naveen/Desktop/example/subject_2/session_2/ltx_2.png'
'/home/naveen/Desktop/example/subject_2/session_2/ltx_2_1.png'
'/home/naveen/Desktop/example/subject_2/session_2/ltx_2_3.png'
'/home/naveen/Desktop/example/subject_2/session_2/ltx_4.png'
'/home/naveen/Desktop/example/subject_2/session_2/ltx_6.png'
Hope this works for you. Please note that in the inner most for loop you have to change the file extension while using for your purpose.

How to divide cell array into array and vector

This is my first time posting so i hope you can help me. I am trying to write a function in matlab.
I have laded data from a file into a cell array. First column contains statements and the second contains T for true og F for false. I now want to split this array into a cell array with the statements and a logical vector with 1 for True and -1 for false.
I use the fgetl within a loop to read all the lines into the cellarray
Try to write it a bit more neatly next time, and consider including a small example.
Here is what you seem to be looking for:
Suppose you have a matrix M and want to split that into M_true and M_false
M = {1,'T';
22,'F';
333,'T'}
idx_T=strcmp(M(:,2),'T')
M_true = M(idx_T,1)
M_false = M(~idx_T,1)

Resources